/[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 14 - (hide annotations)
Mon Oct 8 16:18:51 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 17791 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.982 2005/10/07 22:45:32 debug Exp $
20050816	Some success in decoding the way the SGI O2 PROM draws graphics
		during bootup; lines/rectangles and bitmaps work, enough to
		show the bootlogo etc. :-)
		Adding more PPC instructions, and (dummy) BAT registers.
20050817	Updating the pckbc to support scancode type 3 keyboards
		(required in order to interact with the SGI O2 PROM).
		Adding more PPC instructions.
20050818	Adding more ARM instructions; general register forms.
		Importing armreg.h from NetBSD (ARM cpu ids). Adding a (dummy)
		CATS machine mode (using SA110 as the default CPU).
		Continuing on general dyntrans related stuff.
20050819	Register forms for ARM load/stores. Gaah! The Compaq C Compiler
		bug is triggered for ARM loads as well, not just PPC :-(
		Adding full support for ARM PC-relative load/stores, and load/
		stores where the PC register is the destination register.
		Adding support for ARM a.out binaries.
20050820	Continuing to add more ARM instructions, and correcting some
		bugs. Continuing on CATS emulation.
		More work on the PPC stuff.
20050821	Minor PPC and ARM updates. Adding more machine types.
20050822	All ARM "data processing instructions" are now generated
		automatically.
20050824	Beginning the work on the ARM system control coprocessor.
		Adding support for ARM halfword load/stores, and signed loads.
20050825	Fixing an important bug related to the ARM condition codes.
		OpenBSD/zaurus and NetBSD/netwinder now print some boot
		messages. :)
		Adding a dummy SH (Hitachi SuperH) cpu family.
		Beginning to add some ARM virtual address translation.
		MIPS bugfixes: unaligned PC now cause an ADEL exception (at
		least for non-bintrans execution), and ADEL/ADES (not
		TLBL/TLBS) are used if userland tries to access kernel space.
		(Thanks to Joshua Wise for making me aware of these bugs.)
20050827	More work on the ARM emulation, and various other updates.
20050828	More ARM updates.
		Finally taking the time to work on translation invalidation
		(i.e. invalidating translated code mappings when memory is
		written to). Hopefully this doesn't break anything.
20050829	Moving CPU related files from src/ to a new subdir, src/cpus/.
		Moving PROM emulation stuff from src/ to src/promemul/.
		Better debug instruction trace for ARM loads and stores.
20050830	Various ARM updates (correcting CMP flag calculation, etc).
20050831	PPC instruction updates. (Flag fixes, etc.)
20050901	Various minor PPC and ARM instruction emulation updates.
		Minor OpenFirmware emulation updates.
20050903	Adding support for adding arbitrary ARM coprocessors (with
		the i80321 I/O coprocessor as a first test).
		Various other ARM and PPC updates.
20050904	Adding some SHcompact disassembly routines.
20050907	(Re)adding a dummy HPPA CPU module, and a dummy i960 module.
20050908	Began hacking on some Apple Partition Table support.
20050909	Adding support for loading Mach-O (Darwin PPC) binaries.
20050910	Fixing an ARM bug (Carry flag was incorrectly updated for some
		data processing instructions); OpenBSD/cats and NetBSD/
		netwinder get quite a bit further now.
		Applying a patch to dev_wdc, and a one-liner to dev_pcic, to
		make them work better when emulating new versions of OpenBSD.
		(Thanks to Alexander Yurchenko for the patches.)
		Also doing some other minor updates to dev_wdc. (Some cleanup,
		and finally converting to devinit, etc.)
20050912	IRIX doesn't have u_int64_t by default (noticed by Andreas
		<avr@gnulinux.nl>); configure updated to reflect this.
		Working on ARM register bank switching, CPSR vs SPSR issues,
		and beginning the work on interrupt/exception support.
20050913	Various minor ARM updates (speeding up load/store multiple,
		and fixing a ROR bug in R(); NetBSD/cats now boots as far as
		OpenBSD/cats).
20050917	Adding a dummy Atmel AVR (8-bit) cpu family skeleton.
20050918	Various minor updates.
20050919	Symbols are now loaded from Mach-O executables.
		Continuing the work on adding ARM exception support.
20050920	More work on ARM stuff: OpenBSD/cats and NetBSD/cats reach
		userland! :-)
20050921	Some more progress on ARM interrupt specifics.
20050923	Fixing linesize for VR4121 (patch by Yurchenko). Also fixing
		linesizes/cachesizes for some other VR4xxx.
		Adding a dummy Acer Labs M1543 PCI-ISA bridge (for CATS) and a
		dummy Symphony Labs 83C553 bridge (for Netwinder), usable by 
		dev_footbridge.
20050924	Some PPC progress.
20050925	More PPC progress.
20050926	PPC progress (fixing some bugs etc); Darwin's kernel gets
		slightly further than before.
20050928	Various updates: footbridge/ISA/pciide stuff, and finally
		fixing the VGA text scroll-by-changing-the-base-offset bug.
20050930	Adding a dummy S3 ViRGE pci card for CATS emulation, which
		both NetBSD and OpenBSD detects as VGA.
		Continuing on Footbridge (timers, ISA interrupt stuff).
20051001	Continuing... there are still bugs, probably interrupt-
		related.
20051002	More work on the Footbridge (interrupt stuff).
20051003	Various minor updates. (Trying to find the bug(s).)
20051004	Continuing on the ARM stuff.
20051005	More ARM-related fixes.
20051007	FINALLY! Found and fixed 2 ARM bugs: 1 memory related, and the
		other was because of an error in the ARM manual (load multiple
		with the S-bit set should _NOT_ load usermode registers, as the
		manual says, but it should load saved registers, which may or
		may not happen to be usermode registers).
		NetBSD/cats and OpenBSD/cats seem to install fine now :-)
		except for a minor bug at the end of the OpenBSD/cats install.
		Updating the documentation, preparing for the next release.
20051008	Continuing with release testing and cleanup.

1 dpavlin 4 /*
2     * Copyright (C) 2004-2005 Anders Gavare. All rights reserved.
3     *
4     * Redistribution and use in source and binary forms, with or without
5     * modification, are permitted provided that the following conditions are met:
6     *
7     * 1. Redistributions of source code must retain the above copyright
8     * notice, this list of conditions and the following disclaimer.
9     * 2. Redistributions in binary form must reproduce the above copyright
10     * notice, this list of conditions and the following disclaimer in the
11     * documentation and/or other materials provided with the distribution.
12     * 3. The name of the author may not be used to endorse or promote products
13     * derived from this software without specific prior written permission.
14     *
15     * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16     * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17     * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18     * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19     * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20     * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21     * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24     * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25     * SUCH DAMAGE.
26     *
27 dpavlin 14 *
28     * $Id: dev_wdc.c,v 1.39 2005/09/27 23:55:44 debug Exp $
29     *
30     * Standard "wdc" IDE controller.
31 dpavlin 4 */
32    
33     #include <stdio.h>
34     #include <stdlib.h>
35     #include <string.h>
36    
37     #include "console.h"
38     #include "cpu.h"
39 dpavlin 14 #include "device.h"
40 dpavlin 4 #include "diskimage.h"
41     #include "machine.h"
42     #include "memory.h"
43     #include "misc.h"
44    
45     #include "wdcreg.h"
46    
47 dpavlin 14 #define DEV_WDC_LENGTH 8
48 dpavlin 4 #define WDC_TICK_SHIFT 14
49     #define WDC_INBUF_SIZE (512*257)
50    
51 dpavlin 14 /*
52     * INT_DELAY=2 to be safe, 1 is faster but maybe buggy. 0 is fastest.
53     *
54     * The only reason for this delay to exist is because (some versions of)
55     * NetBSD for hpcmips have interrupt problems. These problems are not only
56     * triggered inside the emulator, but also on real hardware. Using the
57     * delay is an ugly (but working) work-around.
58     */
59 dpavlin 4 #define INT_DELAY 1
60    
61 dpavlin 6 extern int quiet_mode;
62    
63 dpavlin 4 /* #define debug fatal */
64    
65     struct wdc_data {
66     int irq_nr;
67     int base_drive;
68 dpavlin 14 int data_debug;
69 dpavlin 4
70 dpavlin 14 /* Cached values: */
71     int cyls[2];
72     int heads[2];
73     int sectors_per_track[2];
74 dpavlin 4
75     unsigned char identify_struct[512];
76    
77     unsigned char inbuf[WDC_INBUF_SIZE];
78     int inbuf_head;
79     int inbuf_tail;
80    
81 dpavlin 14 int delayed_interrupt;
82 dpavlin 4 int write_in_progress;
83     int write_count;
84     int64_t write_offset;
85    
86     int error;
87     int precomp;
88     int seccnt;
89     int sector;
90     int cyl_lo;
91     int cyl_hi;
92     int sectorsize;
93     int lba;
94     int drive;
95     int head;
96     int cur_command;
97     };
98    
99    
100     /*
101     * dev_wdc_tick():
102     */
103     void dev_wdc_tick(struct cpu *cpu, void *extra)
104     {
105     struct wdc_data *d = extra;
106    
107     if (d->delayed_interrupt) {
108     d->delayed_interrupt --;
109    
110     if (d->delayed_interrupt == 0)
111     cpu_interrupt(cpu, d->irq_nr);
112     }
113     }
114    
115    
116     /*
117     * wdc_addtoinbuf():
118     *
119     * Write to the inbuf at its head, read at its tail.
120     */
121     static void wdc_addtoinbuf(struct wdc_data *d, int c)
122     {
123     d->inbuf[d->inbuf_head] = c;
124    
125     d->inbuf_head = (d->inbuf_head + 1) % WDC_INBUF_SIZE;
126     if (d->inbuf_head == d->inbuf_tail)
127 dpavlin 6 fatal("[ wdc_addtoinbuf(): WARNING! wdc inbuf overrun ]\n");
128 dpavlin 4 }
129    
130    
131     /*
132     * wdc_get_inbuf():
133     *
134     * Read from the tail of inbuf.
135     */
136     static uint64_t wdc_get_inbuf(struct wdc_data *d)
137     {
138     int c = d->inbuf[d->inbuf_tail];
139    
140     if (d->inbuf_head == d->inbuf_tail) {
141 dpavlin 6 fatal("[ wdc: WARNING! someone is reading too much from the "
142     "wdc inbuf! ]\n");
143 dpavlin 4 return -1;
144     }
145    
146     d->inbuf_tail = (d->inbuf_tail + 1) % WDC_INBUF_SIZE;
147     return c;
148     }
149    
150    
151     /*
152     * wdc_initialize_identify_struct(d):
153     */
154     static void wdc_initialize_identify_struct(struct cpu *cpu, struct wdc_data *d)
155     {
156 dpavlin 6 uint64_t total_size;
157 dpavlin 14 char namebuf[40];
158 dpavlin 4
159 dpavlin 6 total_size = diskimage_getsize(cpu->machine, d->drive + d->base_drive,
160     DISKIMAGE_IDE);
161 dpavlin 4
162     memset(d->identify_struct, 0, sizeof(d->identify_struct));
163    
164     /* Offsets are in 16-bit WORDS! High byte, then low. */
165    
166     /* 0: general flags */
167     d->identify_struct[2 * 0 + 0] = 0;
168     d->identify_struct[2 * 0 + 1] = 1 << 6;
169    
170     /* 1: nr of cylinders */
171 dpavlin 14 d->identify_struct[2 * 1 + 0] = (d->cyls[d->drive] >> 8);
172     d->identify_struct[2 * 1 + 1] = d->cyls[d->drive] & 255;
173 dpavlin 4
174     /* 3: nr of heads */
175 dpavlin 14 d->identify_struct[2 * 3 + 0] = d->heads[d->drive] >> 8;
176     d->identify_struct[2 * 3 + 1] = d->heads[d->drive];
177 dpavlin 4
178     /* 6: sectors per track */
179 dpavlin 14 d->identify_struct[2 * 6 + 0] = d->sectors_per_track[d->drive] >> 8;
180     d->identify_struct[2 * 6 + 1] = d->sectors_per_track[d->drive];
181 dpavlin 4
182     /* 10-19: Serial number */
183     memcpy(&d->identify_struct[2 * 10], "S/N 1234-5678 ", 20);
184    
185     /* 23-26: Firmware version */
186     memcpy(&d->identify_struct[2 * 23], "VER 1.0 ", 8);
187    
188     /* 27-46: Model number */
189 dpavlin 14 if (diskimage_getname(cpu->machine, d->drive + d->base_drive,
190     DISKIMAGE_IDE, namebuf, sizeof(namebuf))) {
191     int i;
192     for (i=0; i<sizeof(namebuf); i++)
193     if (namebuf[i] == 0) {
194     for (; i<sizeof(namebuf); i++)
195     namebuf[i] = ' ';
196     break;
197     }
198     memcpy(&d->identify_struct[2 * 27], namebuf, 40);
199     } else
200     memcpy(&d->identify_struct[2 * 27],
201     "Fake GXemul IDE disk ", 40);
202 dpavlin 4
203     /* 47: max sectors per multitransfer */
204     d->identify_struct[2 * 47 + 0] = 0x80;
205     d->identify_struct[2 * 47 + 1] = 1; /* 1 or 16? */
206    
207     /* 57-58: current capacity in sectors */
208     d->identify_struct[2 * 57 + 0] = ((total_size / 512) >> 24) % 255;
209     d->identify_struct[2 * 57 + 1] = ((total_size / 512) >> 16) % 255;
210     d->identify_struct[2 * 58 + 0] = ((total_size / 512) >> 8) % 255;
211     d->identify_struct[2 * 58 + 1] = (total_size / 512) & 255;
212    
213     /* 60-61: total nr of addresable sectors */
214     d->identify_struct[2 * 60 + 0] = ((total_size / 512) >> 24) % 255;
215     d->identify_struct[2 * 60 + 1] = ((total_size / 512) >> 16) % 255;
216     d->identify_struct[2 * 61 + 0] = ((total_size / 512) >> 8) % 255;
217     d->identify_struct[2 * 61 + 1] = (total_size / 512) & 255;
218    
219     }
220    
221    
222     /*
223 dpavlin 14 * wdc__read():
224     */
225     void wdc__read(struct cpu *cpu, struct wdc_data *d)
226     {
227     unsigned char buf[512];
228     int i, cyl = d->cyl_hi * 256+ d->cyl_lo;
229     int count = d->seccnt? d->seccnt : 256;
230     uint64_t offset = 512 * (d->sector - 1
231     + d->head * d->sectors_per_track[d->drive] +
232     d->heads[d->drive] * d->sectors_per_track[d->drive] * cyl);
233    
234     #if 0
235     /* LBA: */
236     if (d->lba)
237     offset = 512 * (((d->head & 0xf) << 24) + (cyl << 8)
238     + d->sector);
239     printf("WDC read from offset %lli\n", (long long)offset);
240     #endif
241    
242     while (count > 0) {
243     diskimage_access(cpu->machine, d->drive + d->base_drive,
244     DISKIMAGE_IDE, 0, offset, buf, 512);
245     /* TODO: result code */
246     for (i=0; i<512; i++)
247     wdc_addtoinbuf(d, buf[i]);
248     offset += 512;
249     count --;
250     }
251    
252     d->delayed_interrupt = INT_DELAY;
253     }
254    
255    
256     /*
257     * wdc__write():
258     */
259     void wdc__write(struct cpu *cpu, struct wdc_data *d)
260     {
261     int cyl = d->cyl_hi * 256+ d->cyl_lo;
262     int count = d->seccnt? d->seccnt : 256;
263     uint64_t offset = 512 * (d->sector - 1
264     + d->head * d->sectors_per_track[d->drive] +
265     d->heads[d->drive] * d->sectors_per_track[d->drive] * cyl);
266     #if 0
267     /* LBA: */
268     if (d->lba)
269     offset = 512 * (((d->head & 0xf) << 24) +
270     (cyl << 8) + d->sector);
271     printf("WDC write to offset %lli\n", (long long)offset);
272     #endif
273    
274     d->write_in_progress = 1;
275     d->write_count = count;
276     d->write_offset = offset;
277    
278     /* TODO: result code? */
279     }
280    
281    
282     /*
283 dpavlin 4 * status_byte():
284 dpavlin 14 *
285     * Return a reasonable status byte corresponding to the controller's current
286     * state.
287 dpavlin 4 */
288     static int status_byte(struct wdc_data *d, struct cpu *cpu)
289     {
290     int odata = 0;
291    
292 dpavlin 14 /*
293     * Modern versions of OpenBSD wants WDCS_DSC. (Thanks to Alexander
294     * Yurchenko for noticing this.)
295     */
296 dpavlin 6 if (diskimage_exist(cpu->machine, d->drive + d->base_drive,
297     DISKIMAGE_IDE))
298 dpavlin 14 odata |= WDCS_DRDY | WDCS_DSC;
299 dpavlin 4 if (d->inbuf_head != d->inbuf_tail)
300     odata |= WDCS_DRQ;
301     if (d->write_in_progress)
302     odata |= WDCS_DRQ;
303     if (d->error)
304     odata |= WDCS_ERR;
305    
306     return odata;
307     }
308    
309    
310     /*
311     * dev_wdc_altstatus_access():
312     */
313     int dev_wdc_altstatus_access(struct cpu *cpu, struct memory *mem,
314     uint64_t relative_addr, unsigned char *data, size_t len,
315     int writeflag, void *extra)
316     {
317     struct wdc_data *d = extra;
318     uint64_t idata = 0, odata = 0;
319    
320     idata = memory_readmax64(cpu, data, len);
321    
322     /* Same as the normal status byte? */
323     odata = status_byte(d, cpu);
324    
325     if (writeflag==MEM_READ)
326     debug("[ wdc: read from ALTSTATUS: 0x%02x ]\n",
327     (int)odata);
328     else
329     debug("[ wdc: write to ALT. CTRL: 0x%02x ]\n",
330     (int)idata);
331    
332     if (writeflag == MEM_READ)
333     memory_writemax64(cpu, data, len, odata);
334    
335     return 1;
336     }
337    
338    
339     /*
340     * dev_wdc_access():
341     */
342     int dev_wdc_access(struct cpu *cpu, struct memory *mem,
343     uint64_t relative_addr, unsigned char *data, size_t len,
344     int writeflag, void *extra)
345     {
346     struct wdc_data *d = extra;
347     uint64_t idata = 0, odata = 0;
348 dpavlin 14 int i;
349 dpavlin 4
350     idata = memory_readmax64(cpu, data, len);
351    
352     switch (relative_addr) {
353    
354     case wd_data: /* 0: data */
355     if (writeflag==MEM_READ) {
356     odata = 0;
357    
358     /* TODO: This is hardcoded for little-endian? */
359    
360     odata += wdc_get_inbuf(d);
361     if (len >= 2)
362     odata += (wdc_get_inbuf(d) << 8);
363     if (len == 4) {
364     odata += (wdc_get_inbuf(d) << 16);
365     odata += (wdc_get_inbuf(d) << 24);
366     }
367    
368 dpavlin 14 if (d->data_debug)
369     debug("[ wdc: read from DATA: 0x%04x ]\n",
370     (int)odata);
371 dpavlin 4 if (d->inbuf_tail != d->inbuf_head)
372     d->delayed_interrupt = INT_DELAY;
373     } else {
374     int inbuf_len;
375 dpavlin 14 if (d->data_debug)
376     debug("[ wdc: write to DATA (len=%i): "
377     "0x%08lx ]\n", (int)len, (long)idata);
378 dpavlin 4 if (!d->write_in_progress) {
379     fatal("[ wdc: write to DATA, but not "
380     "expecting any? (len=%i): 0x%08lx ]\n",
381     (int)len, (long)idata);
382     }
383    
384     switch (len) {
385     case 4: wdc_addtoinbuf(d, idata & 0xff);
386     wdc_addtoinbuf(d, (idata >> 8) & 0xff);
387     wdc_addtoinbuf(d, (idata >> 16) & 0xff);
388     wdc_addtoinbuf(d, (idata >> 24) & 0xff);
389     break;
390     case 2: wdc_addtoinbuf(d, idata & 0xff);
391     wdc_addtoinbuf(d, (idata >> 8) & 0xff);
392     break;
393     case 1: wdc_addtoinbuf(d, idata); break;
394     default:fatal("wdc: unimplemented write len %i\n", len);
395     exit(1);
396     }
397    
398     inbuf_len = d->inbuf_head - d->inbuf_tail;
399     while (inbuf_len < 0)
400     inbuf_len += WDC_INBUF_SIZE;
401    
402     #if 0
403     if ((inbuf_len % (512 * d->write_count)) == 0) {
404 dpavlin 14 #else
405     if ((inbuf_len % 512) == 0) {
406 dpavlin 4 #endif
407     int count = 1; /* d->write_count; */
408     unsigned char *buf = malloc(count * 512);
409     if (buf == NULL) {
410     fprintf(stderr, "out of memory\n");
411     exit(1);
412     }
413    
414     for (i=0; i<512 * count; i++)
415     buf[i] = wdc_get_inbuf(d);
416    
417     diskimage_access(cpu->machine,
418 dpavlin 6 d->drive + d->base_drive, DISKIMAGE_IDE, 1,
419 dpavlin 4 d->write_offset, buf, 512 * count);
420     free(buf);
421    
422     d->write_count --;
423     d->write_offset += 512;
424    
425     d->delayed_interrupt = INT_DELAY;
426    
427     if (d->write_count == 0)
428     d->write_in_progress = 0;
429     }
430     }
431     break;
432    
433     case wd_error: /* 1: error (r), precomp (w) */
434     if (writeflag==MEM_READ) {
435     odata = d->error;
436 dpavlin 14 debug("[ wdc: read from ERROR: 0x%02x ]\n",
437     (int)odata);
438 dpavlin 4 /* TODO: is the error value cleared on read? */
439     d->error = 0;
440     } else {
441     d->precomp = idata;
442 dpavlin 14 debug("[ wdc: write to PRECOMP: 0x%02x ]\n",(int)idata);
443 dpavlin 4 }
444     break;
445    
446     case wd_seccnt: /* 2: sector count */
447     if (writeflag==MEM_READ) {
448     odata = d->seccnt;
449 dpavlin 14 debug("[ wdc: read from SECCNT: 0x%02x ]\n",(int)odata);
450 dpavlin 4 } else {
451     d->seccnt = idata;
452 dpavlin 14 debug("[ wdc: write to SECCNT: 0x%02x ]\n", (int)idata);
453 dpavlin 4 }
454     break;
455    
456     case wd_sector: /* 3: first sector */
457     if (writeflag==MEM_READ) {
458     odata = d->sector;
459 dpavlin 14 debug("[ wdc: read from SECTOR: 0x%02x ]\n",(int)odata);
460 dpavlin 4 } else {
461     d->sector = idata;
462 dpavlin 14 debug("[ wdc: write to SECTOR: 0x%02x ]\n", (int)idata);
463 dpavlin 4 }
464     break;
465    
466     case wd_cyl_lo: /* 4: cylinder low */
467     if (writeflag==MEM_READ) {
468     odata = d->cyl_lo;
469 dpavlin 14 debug("[ wdc: read from CYL_LO: 0x%02x ]\n",(int)odata);
470 dpavlin 4 } else {
471     d->cyl_lo = idata;
472 dpavlin 14 debug("[ wdc: write to CYL_LO: 0x%02x ]\n", (int)idata);
473 dpavlin 4 }
474     break;
475    
476     case wd_cyl_hi: /* 5: cylinder low */
477     if (writeflag==MEM_READ) {
478     odata = d->cyl_hi;
479 dpavlin 14 debug("[ wdc: read from CYL_HI: 0x%02x ]\n",(int)odata);
480 dpavlin 4 } else {
481     d->cyl_hi = idata;
482 dpavlin 14 debug("[ wdc: write to CYL_HI: 0x%02x ]\n", (int)idata);
483 dpavlin 4 }
484     break;
485    
486     case wd_sdh: /* 6: sectorsize/drive/head */
487     if (writeflag==MEM_READ) {
488     odata = (d->sectorsize << 6) + (d->lba << 5) +
489     (d->drive << 4) + (d->head);
490     debug("[ wdc: read from SDH: 0x%02x (sectorsize %i,"
491     " lba=%i, drive %i, head %i) ]\n", (int)odata,
492     d->sectorsize, d->lba, d->drive, d->head);
493     } else {
494     d->sectorsize = (idata >> 6) & 3;
495     d->lba = (idata >> 5) & 1;
496     d->drive = (idata >> 4) & 1;
497     d->head = idata & 0xf;
498     debug("[ wdc: write to SDH: 0x%02x (sectorsize %i,"
499     " lba=%i, drive %i, head %i) ]\n", (int)idata,
500     d->sectorsize, d->lba, d->drive, d->head);
501     }
502     break;
503    
504     case wd_command: /* 7: command or status */
505     if (writeflag==MEM_READ) {
506     odata = status_byte(d, cpu);
507 dpavlin 6 if (!quiet_mode)
508     debug("[ wdc: read from STATUS: 0x%02x ]\n",
509 dpavlin 14 (int)odata);
510 dpavlin 4 cpu_interrupt_ack(cpu, d->irq_nr);
511     d->delayed_interrupt = 0;
512     } else {
513 dpavlin 14 debug("[ wdc: write to COMMAND: 0x%02x ]\n",(int)idata);
514 dpavlin 4 d->cur_command = idata;
515    
516     /* TODO: Is this correct behaviour? */
517     if (!diskimage_exist(cpu->machine,
518 dpavlin 6 d->drive + d->base_drive, DISKIMAGE_IDE)) {
519 dpavlin 4 d->error |= WDCE_ABRT;
520     d->delayed_interrupt = INT_DELAY;
521     break;
522     }
523    
524     /* Handle the command: */
525     switch (d->cur_command) {
526 dpavlin 14
527 dpavlin 4 case WDCC_READ:
528 dpavlin 14 if (!quiet_mode)
529     debug("[ wdc: READ from drive %i, head"
530     " %i, cyl %i, sector %i, nsecs %i "
531     "]\n", d->drive, d->head,
532     d->cyl_hi*256+d->cyl_lo, d->sector,
533     d->seccnt);
534     wdc__read(cpu, d);
535     break;
536 dpavlin 6
537 dpavlin 4 case WDCC_WRITE:
538 dpavlin 14 if (!quiet_mode)
539     debug("[ wdc: WRITE to drive %i, head"
540     " %i, cyl %i, sector %i, nsecs %i"
541     " ]\n", d->drive, d->head,
542     d->cyl_hi*256+d->cyl_lo, d->sector,
543     d->seccnt);
544     wdc__write(cpu, d);
545 dpavlin 4 break;
546    
547     case WDCC_IDP: /* Initialize drive parameters */
548     debug("[ wdc: IDP drive %i (TODO) ]\n",
549     d->drive);
550     /* TODO */
551     d->delayed_interrupt = INT_DELAY;
552     break;
553 dpavlin 14
554 dpavlin 4 case SET_FEATURES:
555     fatal("[ wdc: SET_FEATURES drive %i (TODO), "
556     "feature 0x%02x ]\n", d->drive, d->precomp);
557     /* TODO */
558     switch (d->precomp) {
559     case WDSF_SET_MODE:
560     fatal("[ wdc: WDSF_SET_MODE drive %i, "
561     "pio/dma flags 0x%02x ]\n",
562     d->drive, d->seccnt);
563     break;
564     default:
565     d->error |= WDCE_ABRT;
566     }
567     /* TODO: always interrupt? */
568     d->delayed_interrupt = INT_DELAY;
569     break;
570 dpavlin 14
571 dpavlin 4 case WDCC_RECAL:
572     debug("[ wdc: RECAL drive %i ]\n", d->drive);
573     d->delayed_interrupt = INT_DELAY;
574     break;
575 dpavlin 14
576 dpavlin 4 case WDCC_IDENTIFY:
577     debug("[ wdc: IDENTIFY drive %i ]\n", d->drive);
578     wdc_initialize_identify_struct(cpu, d);
579     /* The IDENTIFY data block is sent out
580     in low/high byte order: */
581     for (i=0; i<sizeof(d->identify_struct); i+=2) {
582     wdc_addtoinbuf(d, d->identify_struct
583     [i+1]);
584     wdc_addtoinbuf(d, d->identify_struct
585     [i+0]);
586     }
587     d->delayed_interrupt = INT_DELAY;
588     break;
589 dpavlin 14
590 dpavlin 4 case WDCC_IDLE_IMMED:
591     debug("[ wdc: IDLE_IMMED drive %i ]\n",
592     d->drive);
593     /* TODO: interrupt here? */
594     d->delayed_interrupt = INT_DELAY;
595     break;
596 dpavlin 14
597     /* Unsupported commands, without warning: */
598     case ATAPI_IDENTIFY_DEVICE:
599     case WDCC_SEC_SET_PASSWORD:
600     case WDCC_SEC_UNLOCK:
601     case WDCC_SEC_ERASE_PREPARE:
602     case WDCC_SEC_ERASE_UNIT:
603     case WDCC_SEC_FREEZE_LOCK:
604     case WDCC_SEC_DISABLE_PASSWORD:
605     d->error |= WDCE_ABRT;
606     break;
607    
608 dpavlin 4 default:
609     /* TODO */
610     d->error |= WDCE_ABRT;
611    
612 dpavlin 14 fatal("[ wdc: WARNING! Unimplemented command "
613     "0x%02x (drive %i, head %i, cyl %i, sector"
614     " %i, nsecs %i) ]\n", d->cur_command,
615     d->drive, d->head, d->cyl_hi*256+d->cyl_lo,
616 dpavlin 4 d->sector, d->seccnt);
617     }
618     }
619     break;
620    
621     default:
622     if (writeflag==MEM_READ)
623     debug("[ wdc: read from 0x%02x ]\n",
624     (int)relative_addr);
625     else
626     debug("[ wdc: write to 0x%02x: 0x%02x ]\n",
627     (int)relative_addr, (int)idata);
628     }
629    
630     if (writeflag == MEM_READ)
631     memory_writemax64(cpu, data, len, odata);
632    
633     return 1;
634     }
635    
636    
637     /*
638 dpavlin 14 * devinit_wdc():
639 dpavlin 4 */
640 dpavlin 14 int devinit_wdc(struct devinit *devinit)
641 dpavlin 4 {
642     struct wdc_data *d;
643     uint64_t alt_status_addr;
644 dpavlin 14 int i;
645 dpavlin 4
646     d = malloc(sizeof(struct wdc_data));
647     if (d == NULL) {
648     fprintf(stderr, "out of memory\n");
649     exit(1);
650     }
651     memset(d, 0, sizeof(struct wdc_data));
652 dpavlin 14 d->irq_nr = devinit->irq_nr;
653 dpavlin 4
654 dpavlin 14 /* base_drive = 0 for the primary controller, 2 for the secondary. */
655     d->base_drive = 0;
656     if ((devinit->addr & 0xfff) == 0x170)
657     d->base_drive = 2;
658 dpavlin 4
659 dpavlin 14 alt_status_addr = devinit->addr + 0x206;
660    
661 dpavlin 4 /* Special hack for pcic/hpcmips: TODO: Fix */
662 dpavlin 14 if (devinit->addr == 0x14000180)
663 dpavlin 4 alt_status_addr = 0x14000386;
664    
665 dpavlin 14 /* Get disk geometries: */
666     for (i=0; i<2; i++)
667     if (diskimage_exist(devinit->machine, d->base_drive +i,
668     DISKIMAGE_IDE))
669     diskimage_getchs(devinit->machine, d->base_drive + i,
670     DISKIMAGE_IDE, &d->cyls[i], &d->heads[i],
671     &d->sectors_per_track[i]);
672 dpavlin 4
673 dpavlin 14 memory_device_register(devinit->machine->memory, "wdc_altstatus",
674     alt_status_addr, 2, dev_wdc_altstatus_access, d, MEM_DEFAULT, NULL);
675     memory_device_register(devinit->machine->memory, devinit->name,
676     devinit->addr, DEV_WDC_LENGTH, dev_wdc_access, d, MEM_DEFAULT,
677     NULL);
678    
679     machine_add_tickfunction(devinit->machine, dev_wdc_tick,
680 dpavlin 4 d, WDC_TICK_SHIFT);
681 dpavlin 14
682     return 1;
683 dpavlin 4 }
684    

  ViewVC Help
Powered by ViewVC 1.1.26