/[gxemul]/trunk/src/devices/dev_wdc.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_wdc.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 24 - (show annotations)
Mon Oct 8 16:19:56 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 25937 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1256 2006/06/23 20:43:44 debug Exp $
20060219	Various minor updates. Removing the old MIPS16 skeleton code,
		because it will need to be rewritten for dyntrans anyway.
20060220-22	Removing the non-working dyntrans backend support.
		Continuing on the 64-bit dyntrans virtual memory generalization.
20060223	More work on the 64-bit vm generalization.
20060225	Beginning on MIPS dyntrans load/store instructions.
		Minor PPC updates (64-bit load/store, etc).
		Fixes for the variable-instruction-length framework, some
		minor AVR updates (a simple Hello World program works!).
		Beginning on a skeleton for automatically generating documen-
		tation (for devices etc.).
20060226	PPC updates (adding some more 64-bit instructions, etc).
		AVR updates (more instructions).
		FINALLY found and fixed the zs bug, making NetBSD/macppc
		accept the serial console.
20060301	Adding more AVR instructions.
20060304	Continuing on AVR-related stuff. Beginning on a framework for
		cycle-accurate device emulation. Adding an experimental "PAL
		TV" device (just a dummy so far).
20060305	Adding more AVR instructions.
		Adding a dummy epcom serial controller (for TS7200 emulation).
20060310	Removing the emul() command from configuration files, so only
		net() and machine() are supported.
		Minor progress on the MIPS dyntrans rewrite.
20060311	Continuing on the MIPS dyntrans rewrite (adding more
		instructions, etc).
20060315	Adding more instructions (sllv, srav, srlv, bgtz[l], blez[l],
		beql, bnel, slti[u], various loads and stores).
20060316	Removing the ALWAYS_SIGNEXTEND_32 option, since it was rarely
		used.
		Adding more MIPS dyntrans instructions, and fixing bugs.
20060318	Implementing fast loads/stores for MIPS dyntrans (big/little
		endian, 32-bit and 64-bit modes).
20060320	Making MIPS dyntrans the default configure option; use
		"--enable-oldmips" to use the old bintrans system.
		Adding MIPS dyntrans dmult[u]; minor updates.
20060322	Continuing... adding some more instructions.
		Adding a simple skeleton for demangling C++ "_ZN" symbols.
20060323	Moving src/debugger.c into a new directory (src/debugger/).
20060324	Fixing the hack used to load PPC ELFs (useful for relocated
		Linux/ppc kernels), and adding a dummy G3 machine mode.
20060325-26	Beginning to experiment with GDB remote serial protocol
		connections; adding a -G command line option for selecting
		which TCP port to listen to.
20060330	Beginning a major cleanup to replace things like "0x%016llx"
		with more correct "0x%016"PRIx64, etc.
		Continuing on the GDB remote serial protocol support.
20060331	More cleanup, and some minor GDB remote progress.
20060402	Adding a hack to the configure script, to allow compilation
		on systems that lack PRIx64 etc.
20060406	Removing the temporary FreeBSD/arm hack in dev_ns16550.c and
		replacing it with a better fix from Olivier Houchard.
20060407	A remote debugger (gdb or ddd) can now start and stop the
		emulator using the GDB remote serial protocol, and registers
		and memory can be read. MIPS only for now.
20060408	More GDB progress: single-stepping also works, and also adding
		support for ARM, PowerPC, and Alpha targets.
		Continuing on the delay-slot-across-page-boundary issue.
20060412	Minor update: beginning to add support for the SPARC target
		to the remote GDB functionality.
20060414	Various MIPS updates: adding more instructions for dyntrans
		(eret, add), and making some exceptions work. Fixing a bug
		in dmult[u].
		Implementing the first SPARC instructions (sethi, or).
20060415	Adding "magic trap" instructions so that PROM calls can be
		software emulated in MIPS dyntrans.
		Adding more MIPS dyntrans instructions (ddiv, dadd) and
		fixing another bug in dmult.
20060416	More MIPS dyntrans progress: adding [d]addi, movn, movz, dsllv,
		rfi, an ugly hack for supporting R2000/R3000 style faked caches,
		preliminary interrupt support, and various other updates and
		bugfixes.
20060417	Adding more SPARC instructions (add, sub, sll[x], sra[x],
		srl[x]), and useful SPARC header definitions.
		Adding the first (trivial) x86/AMD64 dyntrans instructions (nop,
		cli/sti, stc/clc, std/cld, simple mov, inc ax). Various other
		x86 updates related to variable instruction length stuff.
		Adding unaligned loads/stores to the MIPS dyntrans mode (but
		still using the pre-dyntrans (slow) imlementation).
20060419	Fixing a MIPS dyntrans exception-in-delay-slot bug.
		Removing the old "show opcode statistics" functionality, since
		it wasn't really useful and isn't implemented for dyntrans.
		Single-stepping (or running with instruction trace) now looks
		ok with dyntrans with delay-slot architectures.
20060420	Minor hacks (removing the -B command line option when compiled
		for non-bintrans, and some other very minor updates).
		Adding (slow) MIPS dyntrans load-linked/store-conditional.
20060422	Applying fixes for bugs discovered by Nils Weller's nwcc
		(static DEC memmap => now per machine, and adding an extern
		keyword in cpu_arm_instr.c).
		Finally found one of the MIPS dyntrans bugs that I've been
		looking for (copy/paste spelling error BIG vs LITTLE endian in
		cpu_mips_instr_loadstore.c for 16-bit fast stores).
		FINALLY found the major MIPS dyntrans bug: slti vs sltiu
		signed/unsigned code in cpu_mips_instr.c. :-)
		Adding more MIPS dyntrans instructions (lwc1, swc1, bgezal[l],
		ctc1, tlt[u], tge[u], tne, beginning on rdhwr).
		NetBSD/hpcmips can now reach userland when using dyntrans :-)
		Adding some more x86 dyntrans instructions.
		Finally removed the old Alpha-specific virtual memory code,
		and replaced it with the generic 64-bit version.
		Beginning to add disassembly support for SPECIAL3 MIPS opcodes.
20060423	Continuing on the delay-slot-across-page-boundary issue;
		adding an end_of_page2 ic slot (like I had planned before, but
		had removed for some reason).
		Adding a quick-and-dirty fallback to legacy coprocessor 1
		code (i.e. skipping dyntrans implementation for now).
		NetBSD/hpcmips and NetBSD/pmax (when running on an emulated
		R4400) can now be installed and run. :-)  (Many bugs left
		to fix, though.)
		Adding more MIPS dyntrans instructions: madd[u], msub[u].
		Cleaning up the SPECIAL2 vs R5900/TX79/C790 "MMI" opcode
		maps somewhat (disassembly and dyntrans instruction decoding).
20060424	Adding an isa_revision field to mips_cpu_types.h, and making
		sure that SPECIAL3 opcodes cause Reserved Instruction
		exceptions on MIPS32/64 revisions lower than 2.
		Adding the SPARC 'ba', 'call', 'jmpl/retl', 'and', and 'xor'
		instructions.
20060425	Removing the -m command line option ("run at most x 
		instructions") and -T ("single_step_on_bad_addr"), because
		they never worked correctly with dyntrans anyway.
		Freshening up the man page.
20060428	Adding more MIPS dyntrans instructions: bltzal[l], idle.
		Enabling MIPS dyntrans compare interrupts.
20060429	FINALLY found the weird dyntrans bug, causing NetBSD etc. to
		behave strangely: some floating point code (conditional
		coprocessor branches) could not be reused from the old
		non-dyntrans code. The "quick-and-dirty fallback" only appeared
		to work. Fixing by implementing bc1* for MIPS dyntrans.
		More MIPS instructions: [d]sub, sdc1, ldc1, dmtc1, dmfc1, cfc0.
		Freshening up MIPS floating point disassembly appearance.
20060430	Continuing on C790/R5900/TX79 disassembly; implementing 128-bit
		"por" and "pextlw".
20060504	Disabling -u (userland emulation) unless compiled as unstable
		development version.
		Beginning on freshening up the testmachine include files,
		to make it easier to reuse those files (placing them in
		src/include/testmachine/), and beginning on a set of "demos"
		or "tutorials" for the testmachine functionality.
		Minor updates to the MIPS GDB remote protocol stub.
		Refreshing doc/experiments.html and gdb_remote.html.
		Enabling Alpha emulation in the stable release configuration,
		even though no guest OSes for Alpha can run yet.
20060505	Adding a generic 'settings' object, which will contain
		references to settable variables (which will later be possible
		to access using the debugger).
20060506	Updating dev_disk and corresponding demo/documentation (and
		switching from SCSI to IDE disk types, so it actually works
		with current test machines :-).
20060510	Adding a -D_LARGEFILE_SOURCE hack for 64-bit Linux hosts,
		so that fseeko() doesn't give a warning.
		Updating the section about how dyntrans works (the "runnable
		IR") in doc/intro.html.
		Instruction updates (some x64=1 checks, some more R5900
		dyntrans stuff: better mul/mult separation from MIPS32/64,
		adding ei and di).
		Updating MIPS cpuregs.h to a newer one (from NetBSD).
		Adding more MIPS dyntrans instructions: deret, ehb.
20060514	Adding disassembly and beginning implementation of SPARC wr
		and wrpr instructions.
20060515	Adding a SUN SPARC machine mode, with dummy SS20 and Ultra1
		machines. Adding the 32-bit "rd psr" instruction.
20060517	Disassembly support for the general SPARC rd instruction.
		Partial implementation of the cmp (subcc) instruction.
		Some other minor updates (making sure that R5900 processors
		start up with the EIE bit enabled, otherwise Linux/playstation2
		receives no interrupts).
20060519	Minor MIPS updates/cleanups.
20060521	Moving the MeshCube machine into evbmips; this seems to work
		reasonably well with a snapshot of a NetBSD MeshCube kernel.
		Cleanup/fix of MIPS config0 register initialization.
20060529	Minor MIPS fixes, including a sign-extension fix to the
		unaligned load/store code, which makes NetBSD/pmax on R3000
		work better with dyntrans. (Ultrix and Linux/DECstation still
		don't work, though.)
20060530	Minor updates to the Alpha machine mode: adding an AlphaBook
		mode, an LCA bus (forwarding accesses to an ISA bus), etc.
20060531	Applying a bugfix for the MIPS dyntrans sc[d] instruction from
		Ondrej Palkovsky. (Many thanks.)
20060601	Minifix to allow ARM immediate msr instruction to not give
		an error for some valid values.
		More Alpha updates.
20060602	Some minor Alpha updates.
20060603	Adding the Alpha cmpbge instruction. NetBSD/alpha prints its
		first boot messages :-) on an emulated Alphabook 1.
20060612	Minor updates; adding a dev_ether.h include file for the
		testmachine ether device. Continuing the hunt for the dyntrans
		bug which makes Linux and Ultrix on DECstation behave
		strangely... FINALLY found it! It seems to be related to
		invalidation of the translation cache, on tlbw{r,i}. There
		also seems to be some remaining interrupt-related problems.
20060614	Correcting the implementation of ldc1/sdc1 for MIPS dyntrans
		(so that it uses 16 32-bit registers if the FR bit in the
		status register is not set).
20060616	REMOVING BINTRANS COMPLETELY!
		Removing the old MIPS interpretation mode.
		Removing the MFHILO_DELAY and instruction delay stuff, because
		they wouldn't work with dyntrans anyway.
20060617	Some documentation updates (adding "NetBSD-archive" to some
		URLs, and new Debian/DECstation installation screenshots).
		Removing the "tracenull" and "enable-caches" configure options.
		Improving MIPS dyntrans performance somewhat (only invalidate
		translations if necessary, on writes to the entryhi register,
		instead of doing it for all cop0 writes).
20060618	More cleanup after the removal of the old MIPS emulation.
		Trying to fix the MIPS dyntrans performance bugs/bottlenecks;
		only semi-successful so far (for R3000).
20060620	Minor update to allow clean compilation again on Tru64/Alpha.
20060622	MIPS cleanup and fixes (removing the pc_last stuff, which
		doesn't make sense with dyntrans anyway, and fixing a cross-
		page-delay-slot-with-exception case in end_of_page).
		Removing the old max_random_cycles_per_chunk stuff, and the
		concept of cycles vs instructions for MIPS emulation.
		FINALLY found and fixed the bug which caused NetBSD/pmax
		clocks to behave strangely (it was a load to the zero register,
		which was treated as a NOP; now it is treated as a load to a
		dummy scratch register).
20060623	Increasing the dyntrans chunk size back to
		N_SAFE_DYNTRANS_LIMIT, instead of N_SAFE_DYNTRANS_LIMIT/2.
		Preparing for a quick release, even though there are known
		bugs, and performance for non-R3000 MIPS emulation is very
		poor. :-/
		Reverting to half the dyntrans chunk size again, because
		NetBSD/cats seemed less stable with full size chunks. :(
		NetBSD/sgimips 3.0 can now run :-)  (With release 0.3.8, only
		NetBSD/sgimips 2.1 worked, not 3.0.)

==============  RELEASE 0.4.0  ==============


1 /*
2 * Copyright (C) 2004-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_wdc.c,v 1.66 2006/04/20 16:59:05 debug Exp $
29 *
30 * Standard "wdc" IDE controller.
31 */
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36
37 #include "cpu.h"
38 #include "device.h"
39 #include "diskimage.h"
40 #include "machine.h"
41 #include "memory.h"
42 #include "misc.h"
43
44 #include "wdcreg.h"
45
46 #define DEV_WDC_LENGTH 8
47 #define WDC_TICK_SHIFT 14
48 #define WDC_MAX_SECTORS 512
49 #define WDC_INBUF_SIZE (512*(WDC_MAX_SECTORS+1))
50
51 /*
52 * INT_DELAY: This is an old hack which only exists because (some versions of)
53 * NetBSD for hpcmips have interrupt problems. These problems are probably not
54 * specific to GXemul, but are also triggered on real hardware.
55 *
56 * See the following URL for more info:
57 * http://mail-index.netbsd.org/port-hpcmips/2004/12/30/0003.html
58 *
59 * NetBSD/malta also bugs out if wdc interrupts come too quickly. Hm.
60 */
61 #define INT_DELAY 1
62
63 extern int quiet_mode;
64
65 /* #define debug fatal */
66
67 struct wdc_data {
68 int irq_nr;
69 int addr_mult;
70 int base_drive;
71 int data_debug;
72
73 /* Cached values: */
74 int cyls[2];
75 int heads[2];
76 int sectors_per_track[2];
77
78 unsigned char *inbuf;
79 int inbuf_head;
80 int inbuf_tail;
81
82 int delayed_interrupt;
83 int int_asserted;
84
85 int write_in_progress;
86 int write_count;
87 int64_t write_offset;
88
89 int error;
90 int precomp;
91 int seccnt;
92 int sector;
93 int cyl_lo;
94 int cyl_hi;
95 int sectorsize;
96 int lba;
97 int drive;
98 int head;
99 int cur_command;
100
101 int atapi_cmd_in_progress;
102 int atapi_phase;
103 struct scsi_transfer *atapi_st;
104 int atapi_len;
105 size_t atapi_received;
106
107 unsigned char identify_struct[512];
108 };
109
110
111 #define COMMAND_RESET 0x100
112
113
114 /*
115 * dev_wdc_tick():
116 */
117 void dev_wdc_tick(struct cpu *cpu, void *extra)
118 {
119 struct wdc_data *d = extra;
120 int old_di = d->delayed_interrupt;
121
122 if (d->delayed_interrupt)
123 d->delayed_interrupt --;
124
125 if (old_di == 1 || d->int_asserted) {
126 cpu_interrupt(cpu, d->irq_nr);
127 d->int_asserted = 1;
128 }
129 }
130
131
132 /*
133 * wdc_addtoinbuf():
134 *
135 * Write to the inbuf at its head, read at its tail.
136 */
137 static void wdc_addtoinbuf(struct wdc_data *d, int c)
138 {
139 d->inbuf[d->inbuf_head] = c;
140
141 d->inbuf_head = (d->inbuf_head + 1) % WDC_INBUF_SIZE;
142 if (d->inbuf_head == d->inbuf_tail)
143 fatal("[ wdc_addtoinbuf(): WARNING! wdc inbuf overrun!"
144 " Increase WDC_MAX_SECTORS. ]\n");
145 }
146
147
148 /*
149 * wdc_get_inbuf():
150 *
151 * Read from the tail of inbuf.
152 */
153 static uint64_t wdc_get_inbuf(struct wdc_data *d)
154 {
155 int c = d->inbuf[d->inbuf_tail];
156
157 if (d->inbuf_head == d->inbuf_tail) {
158 fatal("[ wdc: WARNING! someone is reading too much from the "
159 "wdc inbuf! ]\n");
160 return -1;
161 }
162
163 d->inbuf_tail = (d->inbuf_tail + 1) % WDC_INBUF_SIZE;
164 return c;
165 }
166
167
168 /*
169 * wdc_initialize_identify_struct():
170 */
171 static void wdc_initialize_identify_struct(struct cpu *cpu, struct wdc_data *d)
172 {
173 uint64_t total_size;
174 int flags, cdrom = 0;
175 char namebuf[40];
176
177 total_size = diskimage_getsize(cpu->machine, d->drive + d->base_drive,
178 DISKIMAGE_IDE);
179 if (diskimage_is_a_cdrom(cpu->machine, d->drive + d->base_drive,
180 DISKIMAGE_IDE))
181 cdrom = 1;
182
183 memset(d->identify_struct, 0, sizeof(d->identify_struct));
184
185 /* Offsets are in 16-bit WORDS! High byte, then low. */
186
187 /* 0: general flags */
188 flags = 1 << 6; /* Fixed */
189 if (cdrom)
190 flags = 0x8580; /* ATAPI, CDROM, removable */
191 d->identify_struct[2 * 0 + 0] = flags >> 8;
192 d->identify_struct[2 * 0 + 1] = flags;
193
194 /* 1: nr of cylinders */
195 d->identify_struct[2 * 1 + 0] = d->cyls[d->drive] >> 8;
196 d->identify_struct[2 * 1 + 1] = d->cyls[d->drive];
197
198 /* 3: nr of heads */
199 d->identify_struct[2 * 3 + 0] = d->heads[d->drive] >> 8;
200 d->identify_struct[2 * 3 + 1] = d->heads[d->drive];
201
202 /* 6: sectors per track */
203 d->identify_struct[2 * 6 + 0] = d->sectors_per_track[d->drive] >> 8;
204 d->identify_struct[2 * 6 + 1] = d->sectors_per_track[d->drive];
205
206 /* 10-19: Serial number */
207 memcpy(&d->identify_struct[2 * 10], "#0 ", 20);
208
209 /* 23-26: Firmware version */
210 memcpy(&d->identify_struct[2 * 23], "1.0 ", 8);
211
212 /* 27-46: Model number */
213 if (diskimage_getname(cpu->machine, d->drive + d->base_drive,
214 DISKIMAGE_IDE, namebuf, sizeof(namebuf))) {
215 size_t i;
216 for (i=0; i<sizeof(namebuf); i++)
217 if (namebuf[i] == 0) {
218 for (; i<sizeof(namebuf); i++)
219 namebuf[i] = ' ';
220 break;
221 }
222 memcpy(&d->identify_struct[2 * 27], namebuf, 40);
223 } else
224 memcpy(&d->identify_struct[2 * 27],
225 "Fake GXemul IDE disk ", 40);
226
227 /* 47: max sectors per multitransfer */
228 d->identify_struct[2 * 47 + 0] = 0x80;
229 d->identify_struct[2 * 47 + 1] = 128;
230
231 /* 49: capabilities: */
232 /* (0x200 = LBA, 0x100 = DMA support.) */
233 d->identify_struct[2 * 49 + 0] = 0;
234 d->identify_struct[2 * 49 + 1] = 0;
235
236 /* 51: PIO timing mode. */
237 d->identify_struct[2 * 51 + 0] = 0x00; /* ? */
238 d->identify_struct[2 * 51 + 1] = 0x00;
239
240 /* 53: 0x02 = fields 64-70 valid, 0x01 = fields 54-58 valid */
241 d->identify_struct[2 * 53 + 0] = 0x00;
242 d->identify_struct[2 * 53 + 1] = 0x02;
243
244 /* 57-58: current capacity in sectors */
245 d->identify_struct[2 * 57 + 0] = ((total_size / 512) >> 24) % 255;
246 d->identify_struct[2 * 57 + 1] = ((total_size / 512) >> 16) % 255;
247 d->identify_struct[2 * 58 + 0] = ((total_size / 512) >> 8) % 255;
248 d->identify_struct[2 * 58 + 1] = (total_size / 512) & 255;
249
250 /* 60-61: total nr of addressable sectors */
251 d->identify_struct[2 * 60 + 0] = ((total_size / 512) >> 24) % 255;
252 d->identify_struct[2 * 60 + 1] = ((total_size / 512) >> 16) % 255;
253 d->identify_struct[2 * 61 + 0] = ((total_size / 512) >> 8) % 255;
254 d->identify_struct[2 * 61 + 1] = (total_size / 512) & 255;
255
256 /* 64: Advanced PIO mode support. 0x02 = mode4, 0x01 = mode3 */
257 d->identify_struct[2 * 64 + 0] = 0x00;
258 d->identify_struct[2 * 64 + 1] = 0x03;
259
260 /* 67, 68: PIO timing */
261 d->identify_struct[2 * 67 + 0] = 0;
262 d->identify_struct[2 * 67 + 1] = 120;
263 d->identify_struct[2 * 68 + 0] = 0;
264 d->identify_struct[2 * 68 + 1] = 120;
265 }
266
267
268 /*
269 * wdc__read():
270 */
271 void wdc__read(struct cpu *cpu, struct wdc_data *d)
272 {
273 #define MAX_SECTORS_PER_CHUNK 64
274 const int max_sectors_per_chunk = MAX_SECTORS_PER_CHUNK;
275 unsigned char buf[512 * MAX_SECTORS_PER_CHUNK];
276 int i, cyl = d->cyl_hi * 256+ d->cyl_lo;
277 int count = d->seccnt? d->seccnt : 256;
278 uint64_t offset = 512 * (d->sector - 1
279 + d->head * d->sectors_per_track[d->drive] +
280 d->heads[d->drive] * d->sectors_per_track[d->drive] * cyl);
281
282 #if 0
283 /* LBA: */
284 if (d->lba)
285 offset = 512 * (((d->head & 0xf) << 24) + (cyl << 8)
286 + d->sector);
287 printf("WDC read from offset %lli\n", (long long)offset);
288 #endif
289
290 while (count > 0) {
291 int to_read = count > max_sectors_per_chunk?
292 max_sectors_per_chunk : count;
293
294 /* TODO: result code from the read? */
295
296 if (d->inbuf_head + 512 * to_read <= WDC_INBUF_SIZE) {
297 diskimage_access(cpu->machine, d->drive + d->base_drive,
298 DISKIMAGE_IDE, 0, offset,
299 d->inbuf + d->inbuf_head, 512 * to_read);
300 d->inbuf_head += 512 * to_read;
301 if (d->inbuf_head == WDC_INBUF_SIZE)
302 d->inbuf_head = 0;
303 } else {
304 diskimage_access(cpu->machine, d->drive + d->base_drive,
305 DISKIMAGE_IDE, 0, offset, buf, 512 * to_read);
306 for (i=0; i<512 * to_read; i++)
307 wdc_addtoinbuf(d, buf[i]);
308 }
309
310 offset += 512 * to_read;
311 count -= to_read;
312 }
313
314 d->delayed_interrupt = INT_DELAY;
315 }
316
317
318 /*
319 * wdc__write():
320 */
321 void wdc__write(struct cpu *cpu, struct wdc_data *d)
322 {
323 int cyl = d->cyl_hi * 256+ d->cyl_lo;
324 int count = d->seccnt? d->seccnt : 256;
325 uint64_t offset = 512 * (d->sector - 1
326 + d->head * d->sectors_per_track[d->drive] +
327 d->heads[d->drive] * d->sectors_per_track[d->drive] * cyl);
328 #if 0
329 /* LBA: */
330 if (d->lba)
331 offset = 512 * (((d->head & 0xf) << 24) +
332 (cyl << 8) + d->sector);
333 printf("WDC write to offset %lli\n", (long long)offset);
334 #endif
335
336 d->write_in_progress = d->cur_command;
337 d->write_count = count;
338 d->write_offset = offset;
339
340 /* TODO: result code? */
341 }
342
343
344 /*
345 * status_byte():
346 *
347 * Return a reasonable status byte corresponding to the controller's current
348 * state.
349 */
350 static int status_byte(struct wdc_data *d, struct cpu *cpu)
351 {
352 int odata = 0;
353 if (diskimage_exist(cpu->machine, d->drive + d->base_drive,
354 DISKIMAGE_IDE))
355 odata |= WDCS_DRDY | WDCS_DSC;
356 if (d->inbuf_head != d->inbuf_tail)
357 odata |= WDCS_DRQ;
358 if (d->write_in_progress)
359 odata |= WDCS_DRQ;
360 if (d->error)
361 odata |= WDCS_ERR;
362 if (d->atapi_cmd_in_progress && (d->atapi_phase & WDCS_DRQ)) {
363 odata |= WDCS_DRQ;
364 }
365 return odata;
366 }
367
368
369 /*
370 * dev_wdc_altstatus_access():
371 */
372 DEVICE_ACCESS(wdc_altstatus)
373 {
374 struct wdc_data *d = extra;
375 uint64_t idata = 0, odata = 0;
376
377 idata = data[0];
378
379 /* Same as the normal status byte: */
380 odata = status_byte(d, cpu);
381
382 if (writeflag==MEM_READ)
383 debug("[ wdc: read from ALTSTATUS: 0x%02x ]\n",
384 (int)odata);
385 else {
386 debug("[ wdc: write to ALT. CTRL: 0x%02x ]\n",
387 (int)idata);
388 if (idata & WDCTL_4BIT)
389 d->cur_command = COMMAND_RESET;
390 }
391
392 if (writeflag == MEM_READ)
393 data[0] = odata;
394
395 return 1;
396 }
397
398
399 /*
400 * wdc_command():
401 */
402 void wdc_command(struct cpu *cpu, struct wdc_data *d, int idata)
403 {
404 size_t i;
405
406 d->cur_command = idata;
407 d->atapi_cmd_in_progress = 0;
408 d->error = 0;
409
410 /*
411 * Disk images that do not exist return an ABORT error. This also
412 * happens with CDROM images with the WDCC_IDENTIFY command; CDROM
413 * images must be detected with ATAPI_IDENTIFY_DEVICE instead.
414 *
415 * TODO: Is this correct/good behaviour?
416 */
417 if (!diskimage_exist(cpu->machine, d->drive + d->base_drive,
418 DISKIMAGE_IDE)) {
419 debug("[ wdc: command 0x%02x drive %i, but no disk image ]\n",
420 d->cur_command, d->drive + d->base_drive);
421 d->error |= WDCE_ABRT;
422 d->delayed_interrupt = INT_DELAY;
423 return;
424 }
425 if (diskimage_is_a_cdrom(cpu->machine, d->drive + d->base_drive,
426 DISKIMAGE_IDE) && d->cur_command == WDCC_IDENTIFY) {
427 debug("[ wdc: IDENTIFY drive %i, but it is an ATAPI "
428 "drive ]\n", d->drive + d->base_drive);
429 d->error |= WDCE_ABRT;
430 d->delayed_interrupt = INT_DELAY;
431 return;
432 }
433
434 /* Handle the command: */
435 switch (d->cur_command) {
436
437 case WDCC_READ:
438 case WDCC_READMULTI:
439 if (!quiet_mode)
440 debug("[ wdc: READ from drive %i, head %i, cyl %i, "
441 "sector %i, nsecs %i ]\n", d->drive, d->head,
442 d->cyl_hi*256+d->cyl_lo, d->sector, d->seccnt);
443 wdc__read(cpu, d);
444 break;
445
446 case WDCC_WRITE:
447 case WDCC_WRITEMULTI:
448 if (!quiet_mode)
449 debug("[ wdc: WRITE to drive %i, head %i, cyl %i, "
450 "sector %i, nsecs %i ]\n", d->drive, d->head,
451 d->cyl_hi*256+d->cyl_lo, d->sector, d->seccnt);
452 wdc__write(cpu, d);
453 break;
454
455 case WDCC_IDP: /* Initialize drive parameters */
456 debug("[ wdc: IDP drive %i (TODO) ]\n", d->drive);
457 /* TODO */
458 d->delayed_interrupt = INT_DELAY;
459 break;
460
461 case SET_FEATURES:
462 debug("[ wdc: SET_FEATURES drive %i (TODO), feature 0x%02x ]\n",
463 d->drive, d->precomp);
464 /* TODO */
465 switch (d->precomp) {
466 case WDSF_SET_MODE:
467 debug("[ wdc: WDSF_SET_MODE drive %i, pio/dma flags "
468 "0x%02x ]\n", d->drive, d->seccnt);
469 break;
470 default:d->error |= WDCE_ABRT;
471 }
472 /* TODO: always interrupt? */
473 d->delayed_interrupt = INT_DELAY;
474 break;
475
476 case WDCC_RECAL:
477 debug("[ wdc: RECAL drive %i ]\n", d->drive);
478 d->delayed_interrupt = INT_DELAY;
479 break;
480
481 case WDCC_IDENTIFY:
482 case ATAPI_IDENTIFY_DEVICE:
483 debug("[ wdc: %sIDENTIFY drive %i ]\n", d->cur_command ==
484 ATAPI_IDENTIFY_DEVICE? "ATAPI " : "", d->drive);
485 wdc_initialize_identify_struct(cpu, d);
486 /* The IDENTIFY data is sent out in low/high byte order: */
487 for (i=0; i<sizeof(d->identify_struct); i+=2) {
488 wdc_addtoinbuf(d, d->identify_struct[i+1]);
489 wdc_addtoinbuf(d, d->identify_struct[i+0]);
490 }
491 d->delayed_interrupt = INT_DELAY;
492 break;
493
494 case WDCC_IDLE_IMMED:
495 debug("[ wdc: IDLE_IMMED drive %i ]\n", d->drive);
496 /* TODO: interrupt here? */
497 d->delayed_interrupt = INT_DELAY;
498 break;
499
500 case WDCC_SETMULTI:
501 debug("[ wdc: SETMULTI drive %i ]\n", d->drive);
502 /* TODO: interrupt here? */
503 d->delayed_interrupt = INT_DELAY;
504 break;
505
506 case ATAPI_SOFT_RESET:
507 debug("[ wdc: ATAPI_SOFT_RESET drive %i ]\n", d->drive);
508 /* TODO: interrupt here? */
509 d->delayed_interrupt = INT_DELAY;
510 break;
511
512 case ATAPI_PKT_CMD:
513 debug("[ wdc: ATAPI_PKT_CMD drive %i ]\n", d->drive);
514 /* TODO: interrupt here? */
515 /* d->delayed_interrupt = INT_DELAY; */
516 d->atapi_cmd_in_progress = 1;
517 d->atapi_phase = PHASE_CMDOUT;
518 break;
519
520 case WDCC_DIAGNOSE:
521 debug("[ wdc: WDCC_DIAGNOSE drive %i: TODO ]\n", d->drive);
522 /* TODO: interrupt here? */
523 d->delayed_interrupt = INT_DELAY;
524 d->error = 1; /* No error? */
525 break;
526
527 /* Unsupported commands, without warning: */
528 case WDCC_SEC_SET_PASSWORD:
529 case WDCC_SEC_UNLOCK:
530 case WDCC_SEC_ERASE_PREPARE:
531 case WDCC_SEC_ERASE_UNIT:
532 case WDCC_SEC_FREEZE_LOCK:
533 case WDCC_SEC_DISABLE_PASSWORD:
534 d->error |= WDCE_ABRT;
535 break;
536
537 default:/* TODO */
538 d->error |= WDCE_ABRT;
539 fatal("[ wdc: WARNING! Unimplemented command 0x%02x (drive %i,"
540 " head %i, cyl %i, sector %i, nsecs %i) ]\n",
541 d->cur_command, d->drive, d->head, d->cyl_hi*256+d->cyl_lo,
542 d->sector, d->seccnt);
543 }
544 }
545
546
547 /*
548 * dev_wdc_access():
549 */
550 DEVICE_ACCESS(wdc)
551 {
552 struct wdc_data *d = extra;
553 uint64_t idata = 0, odata = 0;
554 int i;
555
556 relative_addr /= d->addr_mult;
557
558 if (writeflag == MEM_WRITE) {
559 if (relative_addr == wd_data)
560 idata = memory_readmax64(cpu, data, len);
561 else {
562 if (len != 1)
563 fatal("[ wdc: WARNING! non-8-bit access! ]\n");
564 idata = data[0];
565 }
566 }
567
568 switch (relative_addr) {
569
570 case wd_data: /* 0: data */
571 if (writeflag == MEM_READ) {
572 odata = wdc_get_inbuf(d);
573
574 if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {
575 if (len >= 2)
576 odata += (wdc_get_inbuf(d) << 8);
577 if (len == 4) {
578 odata += (wdc_get_inbuf(d) << 16);
579 odata += (wdc_get_inbuf(d) << 24);
580 }
581 } else {
582 if (len >= 2)
583 odata = (odata << 8) + wdc_get_inbuf(d);
584 if (len == 4) {
585 odata = (odata << 8) + wdc_get_inbuf(d);
586 odata = (odata << 8) + wdc_get_inbuf(d);
587 }
588 }
589
590 if (d->data_debug) {
591 char *s = "0x%04"PRIx64" ]\n";
592 if (len == 1)
593 s = "0x%02"PRIx64" ]\n";
594 if (len == 4)
595 s = "0x%08"PRIx64" ]\n";
596 if (len == 8)
597 s = "0x%016"PRIx64" ]\n";
598 debug("[ wdc: read from DATA: ");
599 debug(s, (uint64_t) odata);
600 }
601
602 if (d->atapi_cmd_in_progress) {
603 d->atapi_len -= len;
604 d->atapi_received += len;
605 if (d->atapi_len == 0) {
606 if (d->atapi_received < d->atapi_st->
607 data_in_len) {
608 d->atapi_phase = PHASE_DATAIN;
609 d->atapi_len = d->atapi_st->
610 data_in_len -
611 d->atapi_received;
612 if (d->atapi_len > 32768)
613 d->atapi_len = 0;
614 } else
615 d->atapi_phase =
616 PHASE_COMPLETED;
617 d->delayed_interrupt = INT_DELAY;
618 }
619 } else {
620 #if 0
621 if (d->inbuf_tail != d->inbuf_head)
622 #else
623 if (d->inbuf_tail != d->inbuf_head &&
624 ((d->inbuf_tail - d->inbuf_head) % 512)
625 == 0)
626 #endif
627 d->delayed_interrupt = INT_DELAY;
628 }
629 } else {
630 int inbuf_len;
631 if (d->data_debug) {
632 char *s = "0x%04"PRIx64" ]\n";
633 if (len == 1)
634 s = "0x%02"PRIx64" ]\n";
635 if (len == 4)
636 s = "0x%08"PRIx64" ]\n";
637 if (len == 8)
638 s = "0x%016"PRIx64" ]\n";
639 debug("[ wdc: write to DATA: ");
640 debug(s, (uint64_t) idata);
641 }
642 if (!d->write_in_progress &&
643 !d->atapi_cmd_in_progress) {
644 fatal("[ wdc: write to DATA, but not "
645 "expecting any? (len=%i): 0x%08lx ]\n",
646 (int)len, (long)idata);
647 }
648
649 if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {
650 switch (len) {
651 case 4: wdc_addtoinbuf(d, idata & 0xff);
652 wdc_addtoinbuf(d, (idata >> 8) & 0xff);
653 wdc_addtoinbuf(d, (idata >> 16) & 0xff);
654 wdc_addtoinbuf(d, (idata >> 24) & 0xff);
655 break;
656 case 2: wdc_addtoinbuf(d, idata & 0xff);
657 wdc_addtoinbuf(d, (idata >> 8) & 0xff);
658 break;
659 case 1: wdc_addtoinbuf(d, idata); break;
660 default:fatal("wdc: unimplemented write "
661 "len %i\n", len);
662 exit(1);
663 }
664 } else {
665 switch (len) {
666 case 4: wdc_addtoinbuf(d, (idata >> 24) & 0xff);
667 wdc_addtoinbuf(d, (idata >> 16) & 0xff);
668 wdc_addtoinbuf(d, (idata >> 8) & 0xff);
669 wdc_addtoinbuf(d, idata & 0xff);
670 break;
671 case 2: wdc_addtoinbuf(d, (idata >> 8) & 0xff);
672 wdc_addtoinbuf(d, idata & 0xff);
673 break;
674 case 1: wdc_addtoinbuf(d, idata); break;
675 default:fatal("wdc: unimplemented write "
676 "len %i\n", len);
677 exit(1);
678 }
679 }
680
681 inbuf_len = d->inbuf_head - d->inbuf_tail;
682 while (inbuf_len < 0)
683 inbuf_len += WDC_INBUF_SIZE;
684
685 if (d->atapi_cmd_in_progress && inbuf_len == 12) {
686 unsigned char *scsi_cmd = malloc(12);
687 int x = 0, res;
688
689 if (d->atapi_st != NULL)
690 scsi_transfer_free(d->atapi_st);
691 d->atapi_st = scsi_transfer_alloc();
692
693 debug("[ wdc: ATAPI command ]\n");
694
695 while (inbuf_len > 0) {
696 scsi_cmd[x++] = wdc_get_inbuf(d);
697 inbuf_len --;
698 }
699
700 d->atapi_st->cmd = scsi_cmd;
701 d->atapi_st->cmd_len = 12;
702
703 if (scsi_cmd[0] == SCSIBLOCKCMD_READ_CAPACITY
704 || scsi_cmd[0] == SCSICMD_READ_10
705 || scsi_cmd[0] == SCSICMD_MODE_SENSE10)
706 d->atapi_st->cmd_len = 10;
707
708 res = diskimage_scsicommand(cpu,
709 d->drive + d->base_drive, DISKIMAGE_IDE,
710 d->atapi_st);
711
712 if (res == 0) {
713 fatal("WDC: ATAPI scsi error?\n");
714 exit(1);
715 }
716
717 d->atapi_len = 0;
718 d->atapi_received = 0;
719
720 if (res == 1) {
721 if (d->atapi_st->data_in != NULL) {
722 int i;
723 d->atapi_phase = PHASE_DATAIN;
724 d->atapi_len = d->atapi_st->
725 data_in_len;
726 for (i=0; i<d->atapi_len; i++)
727 wdc_addtoinbuf(d,
728 d->atapi_st->
729 data_in[i]);
730 if (d->atapi_len > 32768)
731 d->atapi_len = 32768;
732 } else {
733 d->atapi_phase =
734 PHASE_COMPLETED;
735 }
736 } else {
737 fatal("wdc atapi Dataout? TODO\n");
738 d->atapi_phase = PHASE_DATAOUT;
739 exit(1);
740 }
741
742 d->delayed_interrupt = INT_DELAY;
743 }
744
745 if (( d->write_in_progress == WDCC_WRITEMULTI &&
746 inbuf_len % (512 * d->write_count) == 0)
747 ||
748 ( d->write_in_progress == WDCC_WRITE &&
749 inbuf_len % 512 == 0) ) {
750 int count = (d->write_in_progress ==
751 WDCC_WRITEMULTI)? d->write_count : 1;
752 unsigned char *buf = malloc(512 * count);
753 unsigned char *b = buf;
754
755 if (buf == NULL) {
756 fprintf(stderr, "out of memory\n");
757 exit(1);
758 }
759
760 if (d->inbuf_tail+512*count <= WDC_INBUF_SIZE) {
761 b = d->inbuf + d->inbuf_tail;
762 d->inbuf_tail = (d->inbuf_tail + 512
763 * count) % WDC_INBUF_SIZE;
764 } else {
765 for (i=0; i<512 * count; i++)
766 buf[i] = wdc_get_inbuf(d);
767 }
768
769 diskimage_access(cpu->machine,
770 d->drive + d->base_drive, DISKIMAGE_IDE, 1,
771 d->write_offset, b, 512 * count);
772
773 d->write_count -= count;
774 d->write_offset += 512 * count;
775
776 d->delayed_interrupt = INT_DELAY;
777
778 if (d->write_count == 0)
779 d->write_in_progress = 0;
780
781 free(buf);
782 }
783 }
784 break;
785
786 case wd_error: /* 1: error (r), precomp (w) */
787 if (writeflag == MEM_READ) {
788 odata = d->error;
789 debug("[ wdc: read from ERROR: 0x%02x ]\n", (int)odata);
790 /* TODO: is the error value cleared on read? */
791 d->error = 0;
792 } else {
793 d->precomp = idata;
794 debug("[ wdc: write to PRECOMP: 0x%02x ]\n",(int)idata);
795 }
796 break;
797
798 case wd_seccnt: /* 2: sector count (or "ireason" for ATAPI) */
799 if (writeflag == MEM_READ) {
800 odata = d->seccnt;
801 if (d->atapi_cmd_in_progress) {
802 odata = d->atapi_phase & (WDCI_CMD | WDCI_IN);
803 }
804 debug("[ wdc: read from SECCNT: 0x%02x ]\n",(int)odata);
805 } else {
806 d->seccnt = idata;
807 debug("[ wdc: write to SECCNT: 0x%02x ]\n", (int)idata);
808 }
809 break;
810
811 case wd_sector: /* 3: first sector */
812 if (writeflag == MEM_READ) {
813 odata = d->sector;
814 debug("[ wdc: read from SECTOR: 0x%02x ]\n",(int)odata);
815 } else {
816 d->sector = idata;
817 debug("[ wdc: write to SECTOR: 0x%02x ]\n", (int)idata);
818 }
819 break;
820
821 case wd_cyl_lo: /* 4: cylinder low */
822 if (writeflag == MEM_READ) {
823 odata = d->cyl_lo;
824 if (d->cur_command == COMMAND_RESET &&
825 diskimage_is_a_cdrom(cpu->machine,
826 d->drive + d->base_drive, DISKIMAGE_IDE))
827 odata = 0x14;
828 if (d->atapi_cmd_in_progress) {
829 int x = d->atapi_len;
830 if (x > 32768)
831 x = 32768;
832 odata = x & 255;
833 }
834 debug("[ wdc: read from CYL_LO: 0x%02x ]\n",(int)odata);
835 } else {
836 d->cyl_lo = idata;
837 debug("[ wdc: write to CYL_LO: 0x%02x ]\n", (int)idata);
838 }
839 break;
840
841 case wd_cyl_hi: /* 5: cylinder high */
842 if (writeflag == MEM_READ) {
843 odata = d->cyl_hi;
844 if (d->cur_command == COMMAND_RESET &&
845 diskimage_is_a_cdrom(cpu->machine,
846 d->drive + d->base_drive, DISKIMAGE_IDE))
847 odata = 0xeb;
848 if (d->atapi_cmd_in_progress) {
849 int x = d->atapi_len;
850 if (x > 32768)
851 x = 32768;
852 odata = (x >> 8) & 255;
853 }
854 debug("[ wdc: read from CYL_HI: 0x%02x ]\n",(int)odata);
855 } else {
856 d->cyl_hi = idata;
857 debug("[ wdc: write to CYL_HI: 0x%02x ]\n", (int)idata);
858 }
859 break;
860
861 case wd_sdh: /* 6: sectorsize/drive/head */
862 if (writeflag==MEM_READ) {
863 odata = (d->sectorsize << 6) + (d->lba << 5) +
864 (d->drive << 4) + (d->head);
865 debug("[ wdc: read from SDH: 0x%02x (sectorsize %i,"
866 " lba=%i, drive %i, head %i) ]\n", (int)odata,
867 d->sectorsize, d->lba, d->drive, d->head);
868 } else {
869 d->sectorsize = (idata >> 6) & 3;
870 d->lba = (idata >> 5) & 1;
871 d->drive = (idata >> 4) & 1;
872 d->head = idata & 0xf;
873 debug("[ wdc: write to SDH: 0x%02x (sectorsize %i,"
874 " lba=%i, drive %i, head %i) ]\n", (int)idata,
875 d->sectorsize, d->lba, d->drive, d->head);
876 }
877 break;
878
879 case wd_command: /* 7: command or status */
880 if (writeflag==MEM_READ) {
881 odata = status_byte(d, cpu);
882 if (!quiet_mode)
883 debug("[ wdc: read from STATUS: 0x%02x ]\n",
884 (int)odata);
885 cpu_interrupt_ack(cpu, d->irq_nr);
886 d->int_asserted = 0;
887 d->delayed_interrupt = 0;
888 } else {
889 debug("[ wdc: write to COMMAND: 0x%02x ]\n",(int)idata);
890 wdc_command(cpu, d, idata);
891 }
892 break;
893
894 default:
895 if (writeflag==MEM_READ)
896 debug("[ wdc: read from 0x%02x ]\n",
897 (int)relative_addr);
898 else
899 debug("[ wdc: write to 0x%02x: 0x%02x ]\n",
900 (int)relative_addr, (int)idata);
901 }
902
903 if (cpu->machine->machine_type != MACHINE_HPCMIPS &&
904 cpu->machine->machine_type != MACHINE_EVBMIPS &&
905 cpu->machine->machine_type != MACHINE_BEBOX)
906 dev_wdc_tick(cpu, extra);
907
908 if (writeflag == MEM_READ) {
909 if (relative_addr == wd_data)
910 memory_writemax64(cpu, data, len, odata);
911 else
912 data[0] = odata;
913 }
914
915 return 1;
916 }
917
918
919 DEVINIT(wdc)
920 {
921 struct wdc_data *d;
922 uint64_t alt_status_addr;
923 int i, tick_shift = WDC_TICK_SHIFT;
924
925 d = malloc(sizeof(struct wdc_data));
926 if (d == NULL) {
927 fprintf(stderr, "out of memory\n");
928 exit(1);
929 }
930 memset(d, 0, sizeof(struct wdc_data));
931 d->irq_nr = devinit->irq_nr;
932 d->addr_mult = devinit->addr_mult;
933 d->data_debug = 1;
934
935 d->inbuf = zeroed_alloc(WDC_INBUF_SIZE);
936
937 /* base_drive = 0 for the primary controller, 2 for the secondary. */
938 d->base_drive = 0;
939 if ((devinit->addr & 0xfff) == 0x170)
940 d->base_drive = 2;
941
942 alt_status_addr = devinit->addr + 0x206;
943
944 /* Special hacks for individual machines: */
945 switch (devinit->machine->machine_type) {
946 case MACHINE_MACPPC:
947 alt_status_addr = devinit->addr + 0x160;
948 break;
949 case MACHINE_HPCMIPS:
950 /* TODO: Fix */
951 if (devinit->addr == 0x14000180)
952 alt_status_addr = 0x14000386;
953 break;
954 case MACHINE_IQ80321:
955 alt_status_addr = devinit->addr + 0x402;
956 break;
957 }
958
959 /* Get disk geometries: */
960 for (i=0; i<2; i++)
961 if (diskimage_exist(devinit->machine, d->base_drive +i,
962 DISKIMAGE_IDE))
963 diskimage_getchs(devinit->machine, d->base_drive + i,
964 DISKIMAGE_IDE, &d->cyls[i], &d->heads[i],
965 &d->sectors_per_track[i]);
966
967 memory_device_register(devinit->machine->memory, "wdc_altstatus",
968 alt_status_addr, 2, dev_wdc_altstatus_access, d, DM_DEFAULT, NULL);
969 memory_device_register(devinit->machine->memory, devinit->name,
970 devinit->addr, DEV_WDC_LENGTH * devinit->addr_mult, dev_wdc_access,
971 d, DM_DEFAULT, NULL);
972
973 if (devinit->machine->machine_type != MACHINE_HPCMIPS &&
974 devinit->machine->machine_type != MACHINE_EVBMIPS)
975 tick_shift += 1;
976
977 machine_add_tickfunction(devinit->machine, dev_wdc_tick,
978 d, tick_shift, 0.0);
979
980 return 1;
981 }
982

  ViewVC Help
Powered by ViewVC 1.1.26