/[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 34 - (hide annotations)
Mon Oct 8 16:21:17 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 25247 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1480 2007/02/19 01:34:42 debug Exp $
20061029	Changing usleep(1) calls in the debugger to usleep(10000)
20061107	Adding a new disk image option (-d o...) which sets the ISO9660
		filesystem base offset; also making some other hacks to allow
		NetBSD/dreamcast and homebrew demos/games to boot directly
		from a filesystem image.
		Moving Dreamcast-specific stuff in the documentation to its
		own page (dreamcast.html).
		Adding a border to the Dreamcast PVR framebuffer.
20061108	Adding a -T command line option (again?), for halting the
		emulator on unimplemented memory accesses.
20061109	Continuing on various SH4 and Dreamcast related things.
		The emulator should now halt on more unimplemented device
		accesses, instead of just printing a warning, forcing me to
		actually implement missing stuff :)
20061111	Continuing on SH4 and Dreamcast stuff.
		Adding a bogus Landisk (SH4) machine mode.
20061112	Implementing some parts of the Dreamcast GDROM device. With
		some ugly hacks, NetBSD can (barely) mount an ISO image.
20061113	NetBSD/dreamcast now starts booting from the Live CD image,
		but crashes randomly quite early on in the boot process.
20061122	Beginning on a skeleton interrupt.h and interrupt.c for the
		new interrupt subsystem.
20061124	Continuing on the new interrupt system; taking the first steps
		to attempt to connect CPUs (SuperH and MIPS) and devices
		(dev_cons and SH4 timer interrupts) to it. Many things will
		probably break from now on.
20061125	Converting dev_ns16550, dev_8253 to the new interrupt system.
		Attempting to begin to convert the ISA bus.
20061130	Incorporating a patch from Brian Foley for the configure
		script, which checks for X11 libs in /usr/X11R6/lib64 (which
		is used on some Linux systems).
20061227	Adding a note in the man page about booting from Dreamcast
		CDROM images (i.e. that no external kernel is needed).
20061229	Continuing on the interrupt system rewrite: beginning to
		convert more devices, adding abort() calls for legacy interrupt
		system calls so that everything now _has_ to be rewritten!
		Almost all machine modes are now completely broken.
20061230	More progress on removing old interrupt code, mostly related
		to the ISA bus + devices, the LCA bus (on AlphaBook1), and
		the Footbridge bus (for CATS). And some minor PCI stuff.
		Connecting the ARM cpu to the new interrupt system.
		The CATS, NetWinder, and QEMU_MIPS machine modes now work with
		the new interrupt system :)
20061231	Connecting PowerPC CPUs to the new interrupt system.
		Making PReP machines (IBM 6050) work again.
		Beginning to convert the GT PCI controller (for e.g. Malta
		and Cobalt emulation). Some things work, but not everything.
		Updating Copyright notices for 2007.
20070101	Converting dev_kn02 from legacy style to devinit; the 3max
		machine mode now works with the new interrupt system :-]
20070105	Beginning to convert the SGI O2 machine to the new interrupt
		system; finally converting O2 (IP32) devices to devinit, etc.
20070106	Continuing on the interrupt system redesign/rewrite; KN01
		(PMAX), KN230, and Dreamcast ASIC interrupts should work again,
		moving out stuff from machine.h and devices.h into the
		corresponding devices, beginning the rewrite of i80321
		interrupts, etc.
20070107	Beginning on the rewrite of Eagle interrupt stuff (PReP, etc).
20070117	Beginning the rewrite of Algor (V3) interrupts (finally
		changing dev_v3 into devinit style).
20070118	Removing the "bus" registry concept from machine.h, because
		it was practically meaningless.
		Continuing on the rewrite of Algor V3 ISA interrupts.
20070121	More work on Algor interrupts; they are now working again,
		well enough to run NetBSD/algor. :-)
20070122	Converting VR41xx (HPCmips) interrupts. NetBSD/hpcmips
		can be installed using the new interrupt system :-)
20070123	Making the testmips mode work with the new interrupt system.
20070127	Beginning to convert DEC5800 devices to devinit, and to the
		new interrupt system.
		Converting Playstation 2 devices to devinit, and converting
		the interrupt system. Also fixing a severe bug: the interrupt
		mask register on Playstation 2 is bitwise _toggled_ on writes.
20070128	Removing the dummy NetGear machine mode and the 8250 device
		(which was only used by the NetGear machine).
		Beginning to convert the MacPPC GC (Grand Central) interrupt
		controller to the new interrupt system.
		Converting Jazz interrupts (PICA61 etc.) to the new interrupt
		system. NetBSD/arc can be installed again :-)
		Fixing the JAZZ timer (hardcoding it at 100 Hz, works with
		NetBSD and it is better than a completely dummy timer as it
		was before).
		Converting dev_mp to the new interrupt system, although I
		haven't had time to actually test it yet.
		Completely removing src/machines/interrupts.c, cpu_interrupt
		and cpu_interrupt_ack in src/cpu.c, and
		src/include/machine_interrupts.h! Adding fatal error messages
		+ abort() in the few places that are left to fix.
		Converting dev_z8530 to the new interrupt system.
		FINALLY removing the md_int struct completely from the
		machine struct.
		SH4 fixes (adding a PADDR invalidation in the ITLB replacement
		code in memory_sh.c); the NetBSD/dreamcast LiveCD now runs
		all the way to the login prompt, and can be interacted with :-)
		Converting the CPC700 controller (PCI and interrupt controller
		for PM/PPC) to the new interrupt system.
20070129	Fixing MACE ISA interrupts (SGI IP32 emulation). Both NetBSD/
		sgimips' and OpenBSD/sgi's ramdisk kernels can now be
		interacted with again.
20070130	Moving out the MIPS multi_lw and _sw instruction combinations
		so that they are auto-generated at compile time instead.
20070131	Adding detection of amd64/x86_64 hosts in the configure script,
		for doing initial experiments (again :-) with native code
		generation.
		Adding a -k command line option to set the size of the dyntrans
		cache, and a -B command line option to disable native code
		generation, even if GXemul was compiled with support for
		native code generation for the specific host CPU architecture.
20070201	Experimenting with a skeleton for native code generation.
		Changing the default behaviour, so that native code generation
		is now disabled by default, and has to be enabled by using
		-b on the command line.
20070202	Continuing the native code generation experiments.
		Making PCI interrupts work for Footbridge again.
20070203	More native code generation experiments.
		Removing most of the native code generation experimental code,
		it does not make sense to include any quick hacks like this.
		Minor cleanup/removal of some more legacy MIPS interrupt code.
20070204	Making i80321 interrupts work again (for NetBSD/evbarm etc.),
		and fixing the timer at 100 Hz.
20070206	Experimenting with removing the wdc interrupt slowness hack.
20070207	Lowering the number of dyntrans TLB entries for MIPS from
		192 to 128, resulting in a minor speed improvement.
		Minor optimization to the code invalidation routine in
		cpu_dyntrans.c.
20070208	Increasing (experimentally) the nr of dyntrans instructions per
		loop from 60 to 120.
20070210	Commenting out (experimentally) the dyntrans_device_danger
		detection in memory_rw.c.
		Changing the testmips and baremips machines to use a revision 2
		MIPS64 CPU by default, instead of revision 1.
		Removing the dummy i960, IA64, x86, AVR32, and HP PA-RISC
		files, the PC bios emulation, and the Olivetti M700 (ARC) and
		db64360 emulation modes.
20070211	Adding an "mp" demo to the demos directory, which tests the
		SMP functionality of the testmips machine.
		Fixing PReP interrupts some more. NetBSD/prep now boots again.
20070216	Adding a "nop workaround" for booting Mach/PMAX to the
		documentation; thanks to Artur Bujdoso for the values.
		Converting more of the MacPPC interrupt stuff to the new
		system.
		Beginning to convert BeBox interrupts to the new system.
		PPC603e should NOT have the PPC_NO_DEC flag! Removing it.
		Correcting BeBox clock speed (it was set to 100 in the NetBSD
		bootinfo block, but should be 33000000/4), allowing NetBSD
		to start without using the (incorrect) PPC_NO_DEC hack.
20070217	Implementing (slow) AltiVec vector loads and stores, allowing
		NetBSD/macppc to finally boot using the GENERIC kernel :-)
		Updating the documentation with install instructions for
		NetBSD/macppc.
20070218-19	Regression testing for the release.

==============  RELEASE 0.4.4  ==============


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 34 * $Id: dev_wdc.c,v 1.74 2007/02/16 19:57:56 debug Exp $
29 dpavlin 14 *
30     * 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     unsigned char *scsi_cmd = malloc(12);
680     int x = 0, res;
681    
682     if (d->atapi_st != NULL)
683     scsi_transfer_free(d->atapi_st);
684     d->atapi_st = scsi_transfer_alloc();
685    
686     debug("[ wdc: ATAPI command ]\n");
687    
688     while (inbuf_len > 0) {
689     scsi_cmd[x++] = wdc_get_inbuf(d);
690     inbuf_len --;
691     }
692    
693     d->atapi_st->cmd = scsi_cmd;
694     d->atapi_st->cmd_len = 12;
695    
696     if (scsi_cmd[0] == SCSIBLOCKCMD_READ_CAPACITY
697     || scsi_cmd[0] == SCSICMD_READ_10
698     || scsi_cmd[0] == SCSICMD_MODE_SENSE10)
699     d->atapi_st->cmd_len = 10;
700    
701     res = diskimage_scsicommand(cpu,
702     d->drive + d->base_drive, DISKIMAGE_IDE,
703     d->atapi_st);
704    
705     if (res == 0) {
706     fatal("WDC: ATAPI scsi error?\n");
707     exit(1);
708     }
709    
710     d->atapi_len = 0;
711     d->atapi_received = 0;
712    
713     if (res == 1) {
714     if (d->atapi_st->data_in != NULL) {
715     int i;
716     d->atapi_phase = PHASE_DATAIN;
717     d->atapi_len = d->atapi_st->
718     data_in_len;
719     for (i=0; i<d->atapi_len; i++)
720     wdc_addtoinbuf(d,
721     d->atapi_st->
722     data_in[i]);
723     if (d->atapi_len > 32768)
724     d->atapi_len = 32768;
725     } else {
726     d->atapi_phase =
727     PHASE_COMPLETED;
728     }
729     } else {
730     fatal("wdc atapi Dataout? TODO\n");
731     d->atapi_phase = PHASE_DATAOUT;
732     exit(1);
733     }
734    
735 dpavlin 34 d->int_assert = 1;
736 dpavlin 20 }
737    
738     if (( d->write_in_progress == WDCC_WRITEMULTI &&
739     inbuf_len % (512 * d->write_count) == 0)
740     ||
741     ( d->write_in_progress == WDCC_WRITE &&
742     inbuf_len % 512 == 0) ) {
743     int count = (d->write_in_progress ==
744     WDCC_WRITEMULTI)? d->write_count : 1;
745 dpavlin 24 unsigned char *buf = malloc(512 * count);
746 dpavlin 18 unsigned char *b = buf;
747    
748 dpavlin 24 if (buf == NULL) {
749     fprintf(stderr, "out of memory\n");
750     exit(1);
751     }
752    
753 dpavlin 18 if (d->inbuf_tail+512*count <= WDC_INBUF_SIZE) {
754     b = d->inbuf + d->inbuf_tail;
755     d->inbuf_tail = (d->inbuf_tail + 512
756     * count) % WDC_INBUF_SIZE;
757     } else {
758     for (i=0; i<512 * count; i++)
759     buf[i] = wdc_get_inbuf(d);
760 dpavlin 4 }
761    
762     diskimage_access(cpu->machine,
763 dpavlin 6 d->drive + d->base_drive, DISKIMAGE_IDE, 1,
764 dpavlin 18 d->write_offset, b, 512 * count);
765 dpavlin 4
766 dpavlin 20 d->write_count -= count;
767     d->write_offset += 512 * count;
768 dpavlin 4
769 dpavlin 34 d->int_assert = 1;
770 dpavlin 4
771     if (d->write_count == 0)
772     d->write_in_progress = 0;
773 dpavlin 24
774     free(buf);
775 dpavlin 4 }
776     }
777     break;
778    
779     case wd_error: /* 1: error (r), precomp (w) */
780 dpavlin 20 if (writeflag == MEM_READ) {
781 dpavlin 4 odata = d->error;
782 dpavlin 22 debug("[ wdc: read from ERROR: 0x%02x ]\n", (int)odata);
783 dpavlin 4 /* TODO: is the error value cleared on read? */
784     d->error = 0;
785     } else {
786     d->precomp = idata;
787 dpavlin 14 debug("[ wdc: write to PRECOMP: 0x%02x ]\n",(int)idata);
788 dpavlin 4 }
789     break;
790    
791 dpavlin 20 case wd_seccnt: /* 2: sector count (or "ireason" for ATAPI) */
792     if (writeflag == MEM_READ) {
793 dpavlin 4 odata = d->seccnt;
794 dpavlin 20 if (d->atapi_cmd_in_progress) {
795     odata = d->atapi_phase & (WDCI_CMD | WDCI_IN);
796     }
797 dpavlin 14 debug("[ wdc: read from SECCNT: 0x%02x ]\n",(int)odata);
798 dpavlin 4 } else {
799     d->seccnt = idata;
800 dpavlin 14 debug("[ wdc: write to SECCNT: 0x%02x ]\n", (int)idata);
801 dpavlin 4 }
802     break;
803    
804     case wd_sector: /* 3: first sector */
805 dpavlin 20 if (writeflag == MEM_READ) {
806 dpavlin 4 odata = d->sector;
807 dpavlin 14 debug("[ wdc: read from SECTOR: 0x%02x ]\n",(int)odata);
808 dpavlin 4 } else {
809     d->sector = idata;
810 dpavlin 14 debug("[ wdc: write to SECTOR: 0x%02x ]\n", (int)idata);
811 dpavlin 4 }
812     break;
813    
814     case wd_cyl_lo: /* 4: cylinder low */
815 dpavlin 20 if (writeflag == MEM_READ) {
816 dpavlin 4 odata = d->cyl_lo;
817 dpavlin 20 if (d->cur_command == COMMAND_RESET &&
818     diskimage_is_a_cdrom(cpu->machine,
819     d->drive + d->base_drive, DISKIMAGE_IDE))
820     odata = 0x14;
821     if (d->atapi_cmd_in_progress) {
822     int x = d->atapi_len;
823     if (x > 32768)
824     x = 32768;
825     odata = x & 255;
826     }
827 dpavlin 14 debug("[ wdc: read from CYL_LO: 0x%02x ]\n",(int)odata);
828 dpavlin 4 } else {
829     d->cyl_lo = idata;
830 dpavlin 14 debug("[ wdc: write to CYL_LO: 0x%02x ]\n", (int)idata);
831 dpavlin 4 }
832     break;
833    
834 dpavlin 20 case wd_cyl_hi: /* 5: cylinder high */
835     if (writeflag == MEM_READ) {
836 dpavlin 4 odata = d->cyl_hi;
837 dpavlin 20 if (d->cur_command == COMMAND_RESET &&
838     diskimage_is_a_cdrom(cpu->machine,
839     d->drive + d->base_drive, DISKIMAGE_IDE))
840     odata = 0xeb;
841     if (d->atapi_cmd_in_progress) {
842     int x = d->atapi_len;
843     if (x > 32768)
844     x = 32768;
845     odata = (x >> 8) & 255;
846     }
847 dpavlin 14 debug("[ wdc: read from CYL_HI: 0x%02x ]\n",(int)odata);
848 dpavlin 4 } else {
849     d->cyl_hi = idata;
850 dpavlin 14 debug("[ wdc: write to CYL_HI: 0x%02x ]\n", (int)idata);
851 dpavlin 4 }
852     break;
853    
854     case wd_sdh: /* 6: sectorsize/drive/head */
855     if (writeflag==MEM_READ) {
856     odata = (d->sectorsize << 6) + (d->lba << 5) +
857     (d->drive << 4) + (d->head);
858     debug("[ wdc: read from SDH: 0x%02x (sectorsize %i,"
859     " lba=%i, drive %i, head %i) ]\n", (int)odata,
860     d->sectorsize, d->lba, d->drive, d->head);
861     } else {
862     d->sectorsize = (idata >> 6) & 3;
863     d->lba = (idata >> 5) & 1;
864     d->drive = (idata >> 4) & 1;
865     d->head = idata & 0xf;
866     debug("[ wdc: write to SDH: 0x%02x (sectorsize %i,"
867     " lba=%i, drive %i, head %i) ]\n", (int)idata,
868     d->sectorsize, d->lba, d->drive, d->head);
869     }
870     break;
871    
872     case wd_command: /* 7: command or status */
873     if (writeflag==MEM_READ) {
874     odata = status_byte(d, cpu);
875 dpavlin 6 if (!quiet_mode)
876     debug("[ wdc: read from STATUS: 0x%02x ]\n",
877 dpavlin 14 (int)odata);
878 dpavlin 34 INTERRUPT_DEASSERT(d->irq);
879     d->int_assert = 0;
880 dpavlin 4 } else {
881 dpavlin 14 debug("[ wdc: write to COMMAND: 0x%02x ]\n",(int)idata);
882 dpavlin 20 wdc_command(cpu, d, idata);
883 dpavlin 4 }
884     break;
885    
886     default:
887     if (writeflag==MEM_READ)
888     debug("[ wdc: read from 0x%02x ]\n",
889     (int)relative_addr);
890     else
891     debug("[ wdc: write to 0x%02x: 0x%02x ]\n",
892     (int)relative_addr, (int)idata);
893     }
894    
895 dpavlin 34 /* Assert interrupt, if necessary: */
896     dev_wdc_tick(cpu, extra);
897 dpavlin 30
898     ret:
899 dpavlin 18 if (writeflag == MEM_READ) {
900     if (relative_addr == wd_data)
901     memory_writemax64(cpu, data, len, odata);
902     else
903     data[0] = odata;
904     }
905    
906 dpavlin 4 return 1;
907     }
908    
909    
910 dpavlin 22 DEVINIT(wdc)
911 dpavlin 4 {
912     struct wdc_data *d;
913     uint64_t alt_status_addr;
914 dpavlin 18 int i, tick_shift = WDC_TICK_SHIFT;
915 dpavlin 4
916     d = malloc(sizeof(struct wdc_data));
917     if (d == NULL) {
918     fprintf(stderr, "out of memory\n");
919     exit(1);
920     }
921     memset(d, 0, sizeof(struct wdc_data));
922 dpavlin 34
923     INTERRUPT_CONNECT(devinit->interrupt_path, d->irq);
924 dpavlin 22 d->addr_mult = devinit->addr_mult;
925 dpavlin 20 d->data_debug = 1;
926 dpavlin 30 d->io_enabled = 1;
927 dpavlin 20
928     d->inbuf = zeroed_alloc(WDC_INBUF_SIZE);
929    
930 dpavlin 14 /* base_drive = 0 for the primary controller, 2 for the secondary. */
931     d->base_drive = 0;
932     if ((devinit->addr & 0xfff) == 0x170)
933     d->base_drive = 2;
934 dpavlin 4
935 dpavlin 14 alt_status_addr = devinit->addr + 0x206;
936    
937 dpavlin 22 /* Special hacks for individual machines: */
938     switch (devinit->machine->machine_type) {
939     case MACHINE_MACPPC:
940     alt_status_addr = devinit->addr + 0x160;
941     break;
942     case MACHINE_HPCMIPS:
943     /* TODO: Fix */
944     if (devinit->addr == 0x14000180)
945     alt_status_addr = 0x14000386;
946     break;
947     case MACHINE_IQ80321:
948     alt_status_addr = devinit->addr + 0x402;
949     break;
950     }
951 dpavlin 4
952 dpavlin 14 /* Get disk geometries: */
953     for (i=0; i<2; i++)
954     if (diskimage_exist(devinit->machine, d->base_drive +i,
955     DISKIMAGE_IDE))
956     diskimage_getchs(devinit->machine, d->base_drive + i,
957     DISKIMAGE_IDE, &d->cyls[i], &d->heads[i],
958     &d->sectors_per_track[i]);
959 dpavlin 4
960 dpavlin 14 memory_device_register(devinit->machine->memory, "wdc_altstatus",
961 dpavlin 20 alt_status_addr, 2, dev_wdc_altstatus_access, d, DM_DEFAULT, NULL);
962 dpavlin 14 memory_device_register(devinit->machine->memory, devinit->name,
963 dpavlin 22 devinit->addr, DEV_WDC_LENGTH * devinit->addr_mult, dev_wdc_access,
964     d, DM_DEFAULT, NULL);
965 dpavlin 14
966     machine_add_tickfunction(devinit->machine, dev_wdc_tick,
967 dpavlin 24 d, tick_shift, 0.0);
968 dpavlin 14
969 dpavlin 30 devinit->return_ptr = d;
970    
971 dpavlin 14 return 1;
972 dpavlin 4 }
973    

  ViewVC Help
Powered by ViewVC 1.1.26