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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 42 - (hide annotations)
Mon Oct 8 16:22:32 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 25163 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1613 2007/06/15 20:11:26 debug Exp $
20070501	Continuing a little on m88k disassembly (control registers,
		more instructions).
		Adding a dummy mvme88k machine mode.
20070502	Re-adding MIPS load/store alignment exceptions.
20070503	Implementing more of the M88K disassembly code.
20070504	Adding disassembly of some more M88K load/store instructions.
		Implementing some relatively simple M88K instructions (br.n,
		xor[.u] imm, and[.u] imm).
20070505	Implementing M88K three-register and, or, xor, and jmp[.n],
		bsr[.n] including function call trace stuff.
		Applying a patch from Bruce M. Simpson which implements the
		SYSCON_BOARD_CPU_CLOCK_FREQ_ID object of the syscon call in
		the yamon PROM emulation.
20070506	Implementing M88K bb0[.n] and bb1[.n], and skeletons for
		ldcr and stcr (although no control regs are implemented yet).
20070509	Found and fixed the bug which caused Linux for QEMU_MIPS to
		stop working in 0.4.5.1: It was a faulty change to the MIPS
		'sc' and 'scd' instructions I made while going through gcc -W
		warnings on 20070428.
20070510	Updating the Linux/QEMU_MIPS section in guestoses.html to
		use mips-test-0.2.tar.gz instead of 0.1.
		A big thank you to Miod Vallat for sending me M88K manuals.
		Implementing more M88K instructions (addu, subu, div[u], mulu,
		ext[u], clr, set, cmp).
20070511	Fixing bugs in the M88K "and" and "and.u" instructions (found
		by comparing against the manual).
		Implementing more M88K instructions (mask[.u], mak, bcnd (auto-
		generated)) and some more control register details.
		Cleanup: Removing the experimental AVR emulation mode and
		corresponding devices; AVR emulation wasn't really meaningful.
		Implementing autogeneration of most M88K loads/stores. The
		rectangle drawing demo (with -O0) for M88K runs :-)
		Beginning on M88K exception handling.
		More M88K instructions: tb0, tb1, rte, sub, jsr[.n].
		Adding some skeleton MVME PROM ("BUG") emulation.
20070512	Fixing a bug in the M88K cmp instruction.
		Adding the M88K lda (scaled register) instruction.
		Fixing bugs in 64-bit (32-bit pairs) M88K loads/stores.
		Removing the unused tick_hz stuff from the machine struct.
		Implementing the M88K xmem instruction. OpenBSD/mvme88k gets
		far enough to display the Copyright banner :-)
		Implementing subu.co (guess), addu.co, addu.ci, ff0, and ff1.
		Adding a dev_mvme187, for MVME187-specific devices/registers.
		OpenBSD/mvme88k prints more boot messages. :)
20070515	Continuing on MVME187 emulation (adding more devices, beginning
		on the CMMUs, etc).
		Adding the M88K and.c, xor.c, and or.c instructions, and making
		sure that mul, div, etc cause exceptions if executed when SFD1
		is disabled.
20070517	Continuing on M88K and MVME187 emulation in general; moving
		the CMMU registers to the CPU struct, separating dev_pcc2 from
		dev_mvme187, and beginning on memory_m88k.c (BATC and PATC).
		Fixing a bug in 64-bit (32-bit pairs) M88K fast stores.
		Implementing the clock part of dev_mk48txx.
		Implementing the M88K fstcr and xcr instructions.
		Implementing m88k_cpu_tlbdump().
		Beginning on the implementation of a separate address space
		for M88K .usr loads/stores.
20070520	Removing the non-working (skeleton) Sandpoint, SonyNEWS, SHARK
		Dnard, and Zaurus machine modes.
		Experimenting with dyntrans to_be_translated read-ahead. It
		seems to give a very small performance increase for MIPS
		emulation, but a large performance degradation for SuperH. Hm.
20070522	Disabling correct SuperH ITLB emulation; it does not seem to be
		necessary in order to let SH4 guest OSes run, and it slows down
		userspace code.
		Implementing "samepage" branches for SuperH emulation, and some
		other minor speed hacks.
20070525	Continuing on M88K memory-related stuff: exceptions, memory
		transaction register contents, etc.
		Implementing the M88K subu.ci instruction.
		Removing the non-working (skeleton) Iyonix machine mode.
		OpenBSD/mvme88k reaches userland :-), starts executing
		/sbin/init's instructions, and issues a few syscalls, before
		crashing.
20070526	Fixing bugs in dev_mk48txx, so that OpenBSD/mvme88k detects
		the correct time-of-day.
		Implementing a generic IRQ controller for the test machines
		(dev_irqc), similar to a proposed patch from Petr Stepan.
		Experimenting some more with translation read-ahead.
		Adding an "expect" script for automated OpenBSD/landisk
		install regression/performance tests.
20070527	Adding a dummy mmEye (SH3) machine mode skeleton.
		FINALLY found the strange M88K bug I have been hunting: I had
		not emulated the SNIP value for exceptions occurring in
		branch delay slots correctly.
		Implementing correct exceptions for 64-bit M88K loads/stores.
		Address to symbol lookups are now disabled when M88K is
		running in usermode (because usermode addresses don't have
		anything to do with supervisor addresses).
20070531	Removing the mmEye machine mode skeleton.
20070604	Some minor code cleanup.
20070605	Moving src/useremul.c into a subdir (src/useremul/), and
		cleaning up some more legacy constructs.
		Adding -Wstrict-aliasing and -fstrict-aliasing detection to
		the configure script.
20070606	Adding a check for broken GCC on Solaris to the configure
		script. (GCC 3.4.3 on Solaris cannot handle static variables
		which are initialized to 0 or NULL. :-/)
		Removing the old (non-working) ARC emulation modes: NEC RD94,
		R94, R96, and R98, and the last traces of Olivetti M700 and
		Deskstation Tyne.
		Removing the non-working skeleton WDSC device (dev_wdsc).
20070607	Thinking about how to use the host's cc + ld at runtime to
		generate native code. (See experiments/native_cc_ld_test.i
		for an example.)
20070608	Adding a program counter sampling timer, which could be useful
		for native code generation experiments.
		The KN02_CSR_NRMMOD bit in the DECstation 5000/200 (KN02) CSR
		should always be set, to allow a 5000/200 PROM to boot.
20070609	Moving out breakpoint details from the machine struct into
		a helper struct, and removing the limit on max nr of
		breakpoints.
20070610	Moving out tick functions into a helper struct as well (which
		also gets rid of the max limit).
20070612	FINALLY figured out why Debian/DECstation stopped working when
		translation read-ahead was enabled: in src/memory_rw.c, the
		call to invalidate_code_translation was made also if the
		memory access was an instruction load (if the page was mapped
		as writable); it shouldn't be called in that case.
20070613	Implementing some more MIPS32/64 revision 2 instructions: di,
		ei, ext, dext, dextm, dextu, and ins.
20070614	Implementing an instruction combination for the NetBSD/arm
		idle loop (making the host not use any cpu if NetBSD/arm
		inside the emulator is not using any cpu).
		Increasing the nr of ARM VPH entries from 128 to 384.
20070615	Removing the ENABLE_arch stuff from the configure script, so
		that all included architectures are included in both release
		and development builds.
		Moving memory related helper functions from misc.c to memory.c.
		Adding preliminary instructions for netbooting NetBSD/pmppc to
		guestoses.html; it doesn't work yet, there are weird timeouts.
		Beginning a total rewrite of the userland emulation modes
		(removing all emulation modes, beginning from scratch with
		NetBSD/MIPS and FreeBSD/Alpha only).
20070616	After fixing a bug in the DEC21143 NIC (the TDSTAT_OWN bit was
		only cleared for the last segment when transmitting, not all
		segments), NetBSD/pmppc boots with root-on-nfs without the
		timeouts. Updating guestoses.html.
		Removing the skeleton PSP (Playstation Portable) mode.
		Moving X11-related stuff in the machine struct into a helper
		struct.
		Cleanup of out-of-memory checks, to use a new CHECK_ALLOCATION
		macro (which prints a meaningful error message).
		Adding a COMMENT to each machine and device (for automagic
		.index comment generation).
		Doing regression testing for the next release.

==============  RELEASE 0.4.6  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26