/[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 32 - (show annotations)
Mon Oct 8 16:20:58 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 19010 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1421 2006/11/06 05:32:37 debug Exp $
20060816	Adding a framework for emulated/virtual timers (src/timer.c),
		using only setitimer().
		Rewriting the mc146818 to use the new timer framework.
20060817	Adding a call to gettimeofday() every now and then (once every
		second, at the moment) to resynch the timer if it drifts.
		Beginning to convert the ISA timer interrupt mechanism (8253
		and 8259) to use the new timer framework.
		Removing the -I command line option.
20060819	Adding the -I command line option again, with new semantics.
		Working on Footbridge timer interrupts; NetBSD/NetWinder and
		NetBSD/CATS now run at correct speed, but unfortunately with
		HUGE delays during bootup.
20060821	Some minor m68k updates. Adding the first instruction: nop. :)
		Minor Alpha emulation updates.
20060822	Adding a FreeBSD development specific YAMON environment
		variable ("khz") (as suggested by Bruce M. Simpson).
		Moving YAMON environment variable initialization from
		machine_evbmips.c into promemul/yamon.c, and adding some more
		variables.
		Continuing on the LCA PCI bus controller (for Alpha machines).
20060823	Continuing on the timer stuff: experimenting with MIPS count/
		compare interrupts connected to the timer framework.
20060825	Adding bogus SCSI commands 0x51 (SCSICDROM_READ_DISCINFO) and
		0x52 (SCSICDROM_READ_TRACKINFO) to the SCSI emulation layer,
		to allow NetBSD/pmax 4.0_BETA to be installed from CDROM.
		Minor updates to the LCA PCI controller.
20060827	Implementing a CHIP8 cpu mode, and a corresponding CHIP8
		machine, for fun. Disassembly support for all instructions,
		and most of the common instructions have been implemented: mvi,
		mov_imm, add_imm, jmp, rand, cls, sprite, skeq_imm, jsr,
		skne_imm, bcd, rts, ldr, str, mov, or, and, xor, add, sub,
		font, ssound, sdelay, gdelay, bogus skup/skpr, skeq, skne.
20060828	Beginning to convert the CHIP8 cpu in the CHIP8 machine to a
		(more correct) RCA 180x cpu. (Disassembly for all 1802
		instructions has been implemented, but no execution yet, and
		no 1805 extended instructions.)
20060829	Minor Alpha emulation updates.
20060830	Beginning to experiment a little with PCI IDE for SGI O2.
		Fixing the cursor key mappings for MobilePro 770 emulation.
		Fixing the LK201 warning caused by recent NetBSD/pmax.
		The MIPS R41xx standby, suspend, and hibernate instructions now
		behave like the RM52xx/MIPS32/MIPS64 wait instruction.
		Fixing dev_wdc so it calculates correct (64-bit) offsets before
		giving them to diskimage_access().
20060831	Continuing on Alpha emulation (OSF1 PALcode).
20060901	Minor Alpha updates; beginning on virtual memory pagetables.
		Removed the limit for max nr of devices (in preparation for
		allowing devices' base addresses to be changed during runtime).
		Adding a hack for MIPS [d]mfc0 select 0 (except the count
		register), so that the coproc register is simply copied.
		The MIPS suspend instruction now exits the emulator, instead
		of being treated as a wait instruction (this causes NetBSD/
		hpcmips to get correct 'halt' behavior).
		The VR41xx RTC now returns correct time.
		Connecting the VR41xx timer to the timer framework (fixed at
		128 Hz, for now).
		Continuing on SPARC emulation, adding more instructions:
		restore, ba_xcc, ble. The rectangle drawing demo works :)
		Removing the last traces of the old ENABLE_CACHE_EMULATION
		MIPS stuff (not usable with dyntrans anyway).
20060902	Splitting up src/net.c into several smaller files in its own
		subdirectory (src/net/).
20060903	Cleanup of the files in src/net/, to make them less ugly.
20060904	Continuing on the 'settings' subsystem.
		Minor progress on the SPARC emulation mode.
20060905	Cleanup of various things, and connecting the settings
		infrastructure to various subsystems (emul, machine, cpu, etc).
		Changing the lk201 mouse update routine to not rely on any
		emulated hardware framebuffer cursor coordinates, but instead
		always do (semi-usable) relative movements.
20060906	Continuing on the lk201 mouse stuff. Mouse behaviour with
		multiple framebuffers (which was working in Ultrix) is now
		semi-broken (but it still works, in a way).
		Moving the documentation about networking into its own file
		(networking.html), and refreshing it a bit. Adding an example
		of how to use ethernet frame direct-access (udp_snoop).
20060907	Continuing on the settings infrastructure.
20060908	Minor updates to SH emulation: for 32-bit emulation: delay
		slots and the 'jsr @Rn' instruction. I'm putting 64-bit SH5 on
		ice, for now.
20060909-10	Implementing some more 32-bit SH instructions. Removing the
		64-bit mode completely. Enough has now been implemented to run
		the rectangle drawing demo. :-)
20060912	Adding more SH instructions.
20060916	Continuing on SH emulation (some more instructions: div0u,
		div1, rotcl/rotcr, more mov instructions, dt, braf, sets, sett,
		tst_imm, dmuls.l, subc, ldc_rm_vbr, movt, clrt, clrs, clrmac).
		Continuing on the settings subsystem (beginning on reading/
		writing settings, removing bugs, and connecting more cpus to
		the framework).
20060919	More work on SH emulation; adding an ldc banked instruction,
		and attaching a 640x480 framebuffer to the Dreamcast machine
		mode (NetBSD/dreamcast prints the NetBSD copyright banner :-),
		and then panics).
20060920	Continuing on the settings subsystem.
20060921	Fixing the Footbridge timer stuff so that NetBSD/cats and
		NetBSD/netwinder boot up without the delays.
20060922	Temporarily hardcoding MIPS timer interrupt to 100 Hz. With
		'wait' support disabled, NetBSD/malta and Linux/malta run at
		correct speed.
20060923	Connecting dev_gt to the timer framework, so that NetBSD/cobalt
		runs at correct speed.
		Moving SH4-specific memory mapped registers into its own
		device (dev_sh4.c).
		Running with -N now prints "idling" instead of bogus nr of
		instrs/second (which isn't valid anyway) while idling.
20060924	Algor emulation should now run at correct speed.
		Adding disassembly support for some MIPS64 revision 2
		instructions: ext, dext, dextm, dextu.
20060926	The timer framework now works also when the MIPS wait
		instruction is used.
20060928	Re-implementing checks for coprocessor availability for MIPS
		cop0 instructions. (Thanks to Carl van Schaik for noticing the
		lack of cop0 availability checks.)
20060929	Implementing an instruction combination hack which treats
		NetBSD/pmax' idle loop as a wait-like instruction.
20060930	The ENTRYHI_R_MASK was missing in (at least) memory_mips_v2p.c,
		causing TLB lookups to sometimes succeed when they should have
		failed. (A big thank you to Juli Mallett for noticing the
		problem.)
		Adding disassembly support for more MIPS64 revision 2 opcodes
		(seb, seh, wsbh, jalr.hb, jr.hb, synci, ins, dins, dinsu,
		dinsm, dsbh, dshd, ror, dror, rorv, drorv, dror32). Also
		implementing seb, seh, dsbh, dshd, and wsbh.
		Implementing an instruction combination hack for Linux/pmax'
		idle loop, similar to the NetBSD/pmax case.
20061001	Changing the NetBSD/sgimips install instructions to extract
		files from an iso image, instead of downloading them via ftp.
20061002	More-than-31-bit userland addresses in memory_mips_v2p.c were
		not actually working; applying a fix from Carl van Schaik to
		enable them to work + making some other updates (adding kuseg
		support).
		Fixing hpcmips (vr41xx) timer initialization.
		Experimenting with O(n)->O(1) reduction in the MIPS TLB lookup
		loop. Seems to work both for R3000 and non-R3000.
20061003	Continuing a little on SH emulation (adding more control
		registers; mini-cleanup of memory_sh.c).
20061004	Beginning on a dev_rtc, a clock/timer device for the test
		machines; also adding a demo, and some documentation.
		Fixing a bug in SH "mov.w @(disp,pc),Rn" (the result wasn't
		sign-extended), and adding the addc and ldtlb instructions.
20061005	Contining on SH emulation: virtual to physical address
		translation, and a skeleton exception mechanism.
20061006	Adding more SH instructions (various loads and stores, rte,
		negc, muls.w, various privileged register-move instructions).
20061007	More SH instructions: various move instructions, trapa, div0s,
		float, fdiv, ftrc.
		Continuing on dev_rtc; removing the rtc demo.
20061008	Adding a dummy Dreamcast PROM module. (Homebrew Dreamcast
		programs using KOS libs need this.)
		Adding more SH instructions: "stc vbr,rn", rotl, rotr, fsca,
		fmul, fadd, various floating-point moves, etc. A 256-byte
		demo for Dreamcast runs :-)
20061012	Adding the SH "lds Rm,pr" and bsr instructions.
20061013	More SH instructions: "sts fpscr,rn", tas.b, and some more
		floating point instructions, cmp/str, and more moves.
		Adding a dummy dev_pvr (Dreamcast graphics controller).
20061014	Generalizing the expression evaluator (used in the built-in
		debugger) to support parentheses and +-*/%^&|.
20061015	Removing the experimental tlb index hint code in
		mips_memory_v2p.c, since it didn't really have any effect.
20061017	Minor SH updates; adding the "sts pr,Rn", fcmp/gt, fneg,
		frchg, and some other instructions. Fixing missing sign-
		extension in an 8-bit load instruction.
20061019	Adding a simple dev_dreamcast_rtc.
		Implementing memory-mapped access to the SH ITLB/UTLB arrays.
20061021	Continuing on various SH and Dreamcast things: sh4 timers,
		debug messages for dev_pvr, fixing some virtual address
		translation bugs, adding the bsrf instruction.
		The NetBSD/dreamcast GENERIC_MD kernel now reaches userland :)
		Adding a dummy dev_dreamcast_asic.c (not really useful yet).
		Implementing simple support for Store Queues.
		Beginning on the PVR Tile Accelerator.
20061022	Generalizing the PVR framebuffer to support off-screen drawing,
		multiple bit-depths, etc. (A small speed penalty, but most
		likely worth it.)
		Adding more SH instructions (mulu.w, fcmp/eq, fsub, fmac,
		fschg, and some more); correcting bugs in "fsca" and "float".
20061024	Adding the SH ftrv (matrix * vector) instruction. Marcus
		Comstedt's "tatest" example runs :) (wireframe only).
		Correcting disassembly for SH floating point instructions that
		use the xd* registers.
		Adding the SH fsts instruction.
		In memory_device_dyntrans_access(), only the currently used
		range is now invalidated, and not the entire device range.
20061025	Adding a dummy AVR32 cpu mode skeleton.
20061026	Various Dreamcast updates; beginning on a Maple bus controller.
20061027	Continuing on the Maple bus. A bogus Controller, Keyboard, and
		Mouse can now be detected by NetBSD and KOS homebrew programs.
		Cleaning up the SH4 Timer Management Unit, and beginning on
		SH4 interrupts.
		Implementing the Dreamcast SYSASIC.
20061028	Continuing on the SYSASIC.
		Adding the SH fsqrt instruction.
		memory_sh.c now actually scans the ITLB.
		Fixing a bug in dev_sh4.c, related to associative writes into
		the memory-mapped UTLB array. NetBSD/dreamcast now reaches
		userland stably, and prints the "Terminal type?" message :-]
		Implementing enough of the Dreamcast keyboard to make NetBSD
		accept it for input.
		Enabling SuperH for stable (non-development) builds.
		Adding NetBSD/dreamcast to the documentation, although it
		doesn't support root-on-nfs yet.
20061029	Changing usleep(1) calls in the debugger to to usleep(10000)
		(according to Brian Foley, this makes GXemul run better on
		MacOS X).
		Making the Maple "Controller" do something (enough to barely
		interact with dcircus.elf).
20061030-31	Some progress on the PVR. More test programs start running (but
		with strange output).
		Various other SH4-related updates.
20061102	Various Dreamcast and SH4 updates; more KOS demos run now.
20061104	Adding a skeleton dev_mb8696x.c (the Dreamcast's LAN adapter).
20061105	Continuing on the MB8696x; NetBSD/dreamcast detects it as mbe0.
		Testing for the release.

==============  RELEASE 0.4.3  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26