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

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

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 4 by dpavlin, Mon Oct 8 16:18:00 2007 UTC revision 34 by dpavlin, Mon Oct 8 16:21:17 2007 UTC
# Line 1  Line 1 
1  /*  /*
2   *  Copyright (C) 2004-2005  Anders Gavare.  All rights reserved.   *  Copyright (C) 2004-2007  Anders Gavare.  All rights reserved.
3   *   *
4   *  Redistribution and use in source and binary forms, with or without   *  Redistribution and use in source and binary forms, with or without
5   *  modification, are permitted provided that the following conditions are met:   *  modification, are permitted provided that the following conditions are met:
# Line 23  Line 23 
23   *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY   *  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   *  OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25   *  SUCH DAMAGE.   *  SUCH DAMAGE.
  *    
26   *   *
27   *  $Id: dev_wdc.c,v 1.33 2005/04/14 20:55:23 debug Exp $   *
28   *     *  $Id: dev_wdc.c,v 1.74 2007/02/16 19:57:56 debug Exp $
29   *  Standard IDE controller.   *
30     *  Standard "wdc" IDE controller.
31   */   */
32    
33  #include <stdio.h>  #include <stdio.h>
34  #include <stdlib.h>  #include <stdlib.h>
35  #include <string.h>  #include <string.h>
36    
 #include "console.h"  
 #include "cop0.h"  
37  #include "cpu.h"  #include "cpu.h"
38  #include "devices.h"  #include "device.h"
39  #include "diskimage.h"  #include "diskimage.h"
40  #include "machine.h"  #include "machine.h"
41  #include "memory.h"  #include "memory.h"
# Line 45  Line 43 
43    
44  #include "wdcreg.h"  #include "wdcreg.h"
45    
46    #define DEV_WDC_LENGTH          8
47  #define WDC_TICK_SHIFT          14  #define WDC_TICK_SHIFT          14
48  #define WDC_INBUF_SIZE          (512*257)  #define WDC_MAX_SECTORS         512
49    #define WDC_INBUF_SIZE          (512*(WDC_MAX_SECTORS+1))
50    
51  /*  INT_DELAY=2 to be safe, 1 is faster but maybe buggy.  */  extern int quiet_mode;
 #define INT_DELAY               1  
52    
53  /*  #define debug fatal  */  /*  #define debug fatal  */
 /*  #define DATA_DEBUG  */  
54    
55  struct wdc_data {  struct wdc_data {
56          int             irq_nr;          struct interrupt irq;
57            int             addr_mult;
58          int             base_drive;          int             base_drive;
59            int             data_debug;
60            int             io_enabled;
61    
62          int             delayed_interrupt;          /*  Cached values:  */
63            int             cyls[2];
64            int             heads[2];
65            int             sectors_per_track[2];
66    
67          unsigned char   identify_struct[512];          unsigned char   *inbuf;
   
         unsigned char   inbuf[WDC_INBUF_SIZE];  
68          int             inbuf_head;          int             inbuf_head;
69          int             inbuf_tail;          int             inbuf_tail;
70    
71            int             int_assert;
72    
73          int             write_in_progress;          int             write_in_progress;
74          int             write_count;          int             write_count;
75          int64_t         write_offset;          int64_t         write_offset;
# Line 82  struct wdc_data { Line 85  struct wdc_data {
85          int             drive;          int             drive;
86          int             head;          int             head;
87          int             cur_command;          int             cur_command;
88    
89            int             atapi_cmd_in_progress;
90            int             atapi_phase;
91            struct scsi_transfer *atapi_st;
92            int             atapi_len;
93            size_t          atapi_received;
94    
95            unsigned char   identify_struct[512];
96  };  };
97    
98    
99  /*  #define COMMAND_RESET   0x100
100   *  dev_wdc_tick():  
101   */  
102  void dev_wdc_tick(struct cpu *cpu, void *extra)  DEVICE_TICK(wdc)
103  {  {
104          struct wdc_data *d = extra;          struct wdc_data *d = extra;
105    
106          if (d->delayed_interrupt) {          if (d->int_assert)
107                  d->delayed_interrupt --;                  INTERRUPT_ASSERT(d->irq);
108    }
109    
110                  if (d->delayed_interrupt == 0)  
111                          cpu_interrupt(cpu, d->irq_nr);  /*
112          }   *  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    
# Line 112  static void wdc_addtoinbuf(struct wdc_da Line 136  static void wdc_addtoinbuf(struct wdc_da
136    
137          d->inbuf_head = (d->inbuf_head + 1) % WDC_INBUF_SIZE;          d->inbuf_head = (d->inbuf_head + 1) % WDC_INBUF_SIZE;
138          if (d->inbuf_head == d->inbuf_tail)          if (d->inbuf_head == d->inbuf_tail)
139                  fatal("WARNING! wdc inbuf overrun\n");                  fatal("[ wdc_addtoinbuf(): WARNING! wdc inbuf overrun!"
140                        " Increase WDC_MAX_SECTORS. ]\n");
141  }  }
142    
143    
# Line 126  static uint64_t wdc_get_inbuf(struct wdc Line 151  static uint64_t wdc_get_inbuf(struct wdc
151          int c = d->inbuf[d->inbuf_tail];          int c = d->inbuf[d->inbuf_tail];
152    
153          if (d->inbuf_head == d->inbuf_tail) {          if (d->inbuf_head == d->inbuf_tail) {
154                  fatal("WARNING! someone is reading too much from the "                  fatal("[ wdc: WARNING! someone is reading too much from the "
155                      "wdc inbuf!\n");                      "wdc inbuf! ]\n");
156                  return -1;                  return -1;
157          }          }
158    
# Line 137  static uint64_t wdc_get_inbuf(struct wdc Line 162  static uint64_t wdc_get_inbuf(struct wdc
162    
163    
164  /*  /*
165   *  wdc_initialize_identify_struct(d):   *  wdc_initialize_identify_struct():
166   */   */
167  static void wdc_initialize_identify_struct(struct cpu *cpu, struct wdc_data *d)  static void wdc_initialize_identify_struct(struct cpu *cpu, struct wdc_data *d)
168  {  {
169          uint64_t total_size, cyls;          uint64_t total_size;
170            int flags, cdrom = 0;
171          total_size = diskimage_getsize(cpu->machine, d->drive + d->base_drive);          char namebuf[40];
172    
173            total_size = diskimage_getsize(cpu->machine, d->drive + d->base_drive,
174                DISKIMAGE_IDE);
175            if (diskimage_is_a_cdrom(cpu->machine, d->drive + d->base_drive,
176                DISKIMAGE_IDE))
177                    cdrom = 1;
178    
179          memset(d->identify_struct, 0, sizeof(d->identify_struct));          memset(d->identify_struct, 0, sizeof(d->identify_struct));
180    
         cyls = total_size / (63 * 16 * 512);  
         if (cyls * 63*16*512 < total_size)  
                 cyls ++;  
   
181          /*  Offsets are in 16-bit WORDS!  High byte, then low.  */          /*  Offsets are in 16-bit WORDS!  High byte, then low.  */
182    
183          /*  0: general flags  */          /*  0: general flags  */
184          d->identify_struct[2 * 0 + 0] = 0;          flags = 1 << 6; /*  Fixed  */
185          d->identify_struct[2 * 0 + 1] = 1 << 6;          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    
190          /*  1: nr of cylinders  */          /*  1: nr of cylinders  */
191          d->identify_struct[2 * 1 + 0] = (cyls >> 8);          d->identify_struct[2 * 1 + 0] = d->cyls[d->drive] >> 8;
192          d->identify_struct[2 * 1 + 1] = cyls & 255;          d->identify_struct[2 * 1 + 1] = d->cyls[d->drive];
193    
194          /*  3: nr of heads  */          /*  3: nr of heads  */
195          d->identify_struct[2 * 3 + 0] = 0;          d->identify_struct[2 * 3 + 0] = d->heads[d->drive] >> 8;
196          d->identify_struct[2 * 3 + 1] = 16;          d->identify_struct[2 * 3 + 1] = d->heads[d->drive];
197    
198          /*  6: sectors per track  */          /*  6: sectors per track  */
199          d->identify_struct[2 * 6 + 0] = 0;          d->identify_struct[2 * 6 + 0] = d->sectors_per_track[d->drive] >> 8;
200          d->identify_struct[2 * 6 + 1] = 63;          d->identify_struct[2 * 6 + 1] = d->sectors_per_track[d->drive];
201    
202          /*  10-19: Serial number  */          /*  10-19: Serial number  */
203          memcpy(&d->identify_struct[2 * 10], "S/N 1234-5678       ", 20);          memcpy(&d->identify_struct[2 * 10], "#0                  ", 20);
204    
205          /*  23-26: Firmware version  */          /*  23-26: Firmware version  */
206          memcpy(&d->identify_struct[2 * 23], "VER 1.0 ", 8);          memcpy(&d->identify_struct[2 * 23], "1.0     ", 8);
207    
208          /*  27-46: Model number  */          /*  27-46: Model number  */
209          memcpy(&d->identify_struct[2 * 27],          if (diskimage_getname(cpu->machine, d->drive + d->base_drive,
210              "Fake GXemul IDE disk                    ", 40);              DISKIMAGE_IDE, namebuf, sizeof(namebuf))) {
211          /*  TODO:  Use the diskimage's filename instead?  */                  size_t i;
212                    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    
223          /*  47: max sectors per multitransfer  */          /*  47: max sectors per multitransfer  */
224          d->identify_struct[2 * 47 + 0] = 0x80;          d->identify_struct[2 * 47 + 0] = 0x80;
225          d->identify_struct[2 * 47 + 1] = 1;     /*  1 or 16?  */          d->identify_struct[2 * 47 + 1] = 128;
226    
227            /*  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          /*  57-58: current capacity in sectors  */          /*  57-58: current capacity in sectors  */
241          d->identify_struct[2 * 57 + 0] = ((total_size / 512) >> 24) % 255;          d->identify_struct[2 * 57 + 0] = ((total_size / 512) >> 24) % 255;
# Line 190  static void wdc_initialize_identify_stru Line 243  static void wdc_initialize_identify_stru
243          d->identify_struct[2 * 58 + 0] = ((total_size / 512) >> 8) % 255;          d->identify_struct[2 * 58 + 0] = ((total_size / 512) >> 8) % 255;
244          d->identify_struct[2 * 58 + 1] = (total_size / 512) & 255;          d->identify_struct[2 * 58 + 1] = (total_size / 512) & 255;
245    
246          /*  60-61: total nr of addresable sectors  */          /*  60-61: total nr of addressable sectors  */
247          d->identify_struct[2 * 60 + 0] = ((total_size / 512) >> 24) % 255;          d->identify_struct[2 * 60 + 0] = ((total_size / 512) >> 24) % 255;
248          d->identify_struct[2 * 60 + 1] = ((total_size / 512) >> 16) % 255;          d->identify_struct[2 * 60 + 1] = ((total_size / 512) >> 16) % 255;
249          d->identify_struct[2 * 61 + 0] = ((total_size / 512) >> 8) % 255;          d->identify_struct[2 * 61 + 0] = ((total_size / 512) >> 8) % 255;
250          d->identify_struct[2 * 61 + 1] = (total_size / 512) & 255;          d->identify_struct[2 * 61 + 1] = (total_size / 512) & 255;
251    
252            /*  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    }
262    
263    
264    /*
265     *  wdc__read():
266     */
267    void wdc__read(struct cpu *cpu, struct wdc_data *d)
268    {
269    #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            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                + (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    
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                    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            }
309    
310            d->int_assert = 1;
311    }
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                + (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    #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            d->write_in_progress = d->cur_command;
333            d->write_count = count;
334            d->write_offset = offset;
335    
336            /*  TODO: result code?  */
337  }  }
338    
339    
340  /*  /*
341   *  status_byte():   *  status_byte():
342     *
343     *  Return a reasonable status byte corresponding to the controller's current
344     *  state.
345   */   */
346  static int status_byte(struct wdc_data *d, struct cpu *cpu)  static int status_byte(struct wdc_data *d, struct cpu *cpu)
347  {  {
348          int odata = 0;          int odata = 0;
349            if (diskimage_exist(cpu->machine, d->drive + d->base_drive,
350          if (diskimage_exist(cpu->machine,              DISKIMAGE_IDE))
351              d->drive + d->base_drive))                  odata |= WDCS_DRDY | WDCS_DSC;
                 odata |= WDCS_DRDY;  
352          if (d->inbuf_head != d->inbuf_tail)          if (d->inbuf_head != d->inbuf_tail)
353                  odata |= WDCS_DRQ;                  odata |= WDCS_DRQ;
354          if (d->write_in_progress)          if (d->write_in_progress)
355                  odata |= WDCS_DRQ;                  odata |= WDCS_DRQ;
356          if (d->error)          if (d->error)
357                  odata |= WDCS_ERR;                  odata |= WDCS_ERR;
358            if (d->atapi_cmd_in_progress && (d->atapi_phase & WDCS_DRQ)) {
359  #if 0                  odata |= WDCS_DRQ;
360          /*          }
          *  TODO:  Is this correct behaviour?  
          *  
          *  NetBSD/cobalt seems to want it, but Linux on MobilePro does not.  
          */  
         if (!diskimage_exist(cpu->machine,  
             d->drive + d->base_drive))  
                 odata = 0xff;  
 #endif  
   
361          return odata;          return odata;
362  }  }
363    
364    
365  /*  DEVICE_ACCESS(wdc_altstatus)
  *  dev_wdc_altstatus_access():  
  */  
 int dev_wdc_altstatus_access(struct cpu *cpu, struct memory *mem,  
         uint64_t relative_addr, unsigned char *data, size_t len,  
         int writeflag, void *extra)  
366  {  {
367          struct wdc_data *d = extra;          struct wdc_data *d = extra;
368          uint64_t idata = 0, odata = 0;          uint64_t idata = 0, odata = 0;
369    
370          idata = memory_readmax64(cpu, data, len);          idata = data[0];
371    
372          /*  Same as the normal status byte?  */          /*  Same as the normal status byte:  */
373          odata = status_byte(d, cpu);          odata = status_byte(d, cpu);
374    
375          if (writeflag==MEM_READ)          if (writeflag==MEM_READ)
376                  debug("[ wdc: read from ALTSTATUS: 0x%02x ]\n",                  debug("[ wdc: read from ALTSTATUS: 0x%02x ]\n",
377                      (int)odata);                      (int)odata);
378          else          else {
379                  debug("[ wdc: write to ALT. CTRL: 0x%02x ]\n",                  debug("[ wdc: write to ALT. CTRL: 0x%02x ]\n",
380                      (int)idata);                      (int)idata);
381                    if (idata & WDCTL_4BIT)
382                            d->cur_command = COMMAND_RESET;
383            }
384    
385          if (writeflag == MEM_READ)          if (writeflag == MEM_READ)
386                  memory_writemax64(cpu, data, len, odata);                  data[0] = odata;
387    
388          return 1;          return 1;
389  }  }
390    
391    
392  /*  /*
393   *  dev_wdc_access():   *  wdc_command():
394   */   */
395  int dev_wdc_access(struct cpu *cpu, struct memory *mem,  void wdc_command(struct cpu *cpu, struct wdc_data *d, int idata)
396          uint64_t relative_addr, unsigned char *data, size_t len,  {
397          int writeflag, void *extra)          size_t i;
398    
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                    d->int_assert = 1;
416                    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                    d->int_assert = 1;
424                    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                    d->int_assert = 1;
452                    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                    d->int_assert = 1;
467                    break;
468    
469            case WDCC_RECAL:
470                    debug("[ wdc: RECAL drive %i ]\n", d->drive);
471                    d->int_assert = 1;
472                    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                    d->int_assert = 1;
485                    break;
486    
487            case WDCC_IDLE_IMMED:
488                    debug("[ wdc: IDLE_IMMED drive %i ]\n", d->drive);
489                    /*  TODO: interrupt here?  */
490                    d->int_assert = 1;
491                    break;
492    
493            case WDCC_SETMULTI:
494                    debug("[ wdc: SETMULTI drive %i ]\n", d->drive);
495                    /*  TODO: interrupt here?  */
496                    d->int_assert = 1;
497                    break;
498    
499            case ATAPI_SOFT_RESET:
500                    debug("[ wdc: ATAPI_SOFT_RESET drive %i ]\n", d->drive);
501                    /*  TODO: interrupt here?  */
502                    d->int_assert = 1;
503                    break;
504    
505            case ATAPI_PKT_CMD:
506                    debug("[ wdc: ATAPI_PKT_CMD drive %i ]\n", d->drive);
507                    /*  TODO: interrupt here?  */
508                    /*  d->int_assert = 1;  */
509                    d->atapi_cmd_in_progress = 1;
510                    d->atapi_phase = PHASE_CMDOUT;
511                    break;
512    
513            case WDCC_DIAGNOSE:
514                    debug("[ wdc: WDCC_DIAGNOSE drive %i: TODO ]\n", d->drive);
515                    /*  TODO: interrupt here?  */
516                    d->int_assert = 1;
517                    d->error = 1;           /*  No error?  */
518                    break;
519    
520            /*  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    DEVICE_ACCESS(wdc)
541  {  {
542          struct wdc_data *d = extra;          struct wdc_data *d = extra;
543          uint64_t idata = 0, odata = 0;          uint64_t idata = 0, odata = 0;
544          int i;          int i;
545    
546          idata = memory_readmax64(cpu, data, len);          relative_addr /= d->addr_mult;
547    
548            if (!d->io_enabled)
549                    goto ret;
550    
551            if (writeflag == MEM_WRITE) {
552                    if (relative_addr == wd_data)
553                            idata = memory_readmax64(cpu, data, len);
554                    else {
555                            if (len != 1)
556                                    fatal("[ wdc: WARNING! non-8-bit access! ]\n");
557                            idata = data[0];
558                    }
559            }
560    
561          switch (relative_addr) {          switch (relative_addr) {
562    
563          case wd_data:   /*  0: data  */          case wd_data:   /*  0: data  */
564                  if (writeflag==MEM_READ) {                  if (writeflag == MEM_READ) {
565                          odata = 0;                          odata = wdc_get_inbuf(d);
566    
567                          /*  TODO: This is hardcoded for little-endian?  */                          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                            }
582    
583                          odata += wdc_get_inbuf(d);                          if (d->data_debug) {
584                          if (len >= 2)                                  char *s = "0x%04"PRIx64" ]\n";
585                                  odata += (wdc_get_inbuf(d) << 8);                                  if (len == 1)
586                          if (len == 4) {                                          s = "0x%02"PRIx64" ]\n";
587                                  odata += (wdc_get_inbuf(d) << 16);                                  if (len == 4)
588                                  odata += (wdc_get_inbuf(d) << 24);                                          s = "0x%08"PRIx64" ]\n";
589                                    if (len == 8)
590                                            s = "0x%016"PRIx64" ]\n";
591                                    debug("[ wdc: read from DATA: ");
592                                    debug(s, (uint64_t) odata);
593                          }                          }
594    
595  #ifdef DATA_DEBUG                          if (d->atapi_cmd_in_progress) {
596                          debug("[ wdc: read from DATA: 0x%04x ]\n", odata);                                  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                                            d->int_assert = 1;
611                                    }
612                            } else {
613    #if 0
614                                    if (d->inbuf_tail != d->inbuf_head)
615    #else
616                                    if (d->inbuf_tail != d->inbuf_head &&
617                                        ((d->inbuf_tail - d->inbuf_head) % 512)
618                                        == 0)
619  #endif  #endif
620                                            d->int_assert = 1;
621                          if (d->inbuf_tail != d->inbuf_head)                          }
                                 d->delayed_interrupt = INT_DELAY;  
   
622                  } else {                  } else {
623                          int inbuf_len;                          int inbuf_len;
624  #ifdef DATA_DEBUG                          if (d->data_debug) {
625                          debug("[ wdc: write to DATA (len=%i): 0x%08lx ]\n",                                  char *s = "0x%04"PRIx64" ]\n";
626                              (int)len, (long)idata);                                  if (len == 1)
627  #endif                                          s = "0x%02"PRIx64" ]\n";
628                          if (!d->write_in_progress) {                                  if (len == 4)
629                                            s = "0x%08"PRIx64" ]\n";
630                                    if (len == 8)
631                                            s = "0x%016"PRIx64" ]\n";
632                                    debug("[ wdc: write to DATA: ");
633                                    debug(s, (uint64_t) idata);
634                            }
635                            if (!d->write_in_progress &&
636                                !d->atapi_cmd_in_progress) {
637                                  fatal("[ wdc: write to DATA, but not "                                  fatal("[ wdc: write to DATA, but not "
638                                      "expecting any? (len=%i): 0x%08lx ]\n",                                      "expecting any? (len=%i): 0x%08lx ]\n",
639                                      (int)len, (long)idata);                                      (int)len, (long)idata);
640                          }                          }
641    
642                          switch (len) {                          if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {
643                          case 4: wdc_addtoinbuf(d, idata & 0xff);                                  switch (len) {
644                                  wdc_addtoinbuf(d, (idata >> 8) & 0xff);                                  case 4: wdc_addtoinbuf(d, idata & 0xff);
645                                  wdc_addtoinbuf(d, (idata >> 16) & 0xff);                                          wdc_addtoinbuf(d, (idata >> 8) & 0xff);
646                                  wdc_addtoinbuf(d, (idata >> 24) & 0xff);                                          wdc_addtoinbuf(d, (idata >> 16) & 0xff);
647                                  break;                                          wdc_addtoinbuf(d, (idata >> 24) & 0xff);
648                          case 2: wdc_addtoinbuf(d, idata & 0xff);                                          break;
649                                  wdc_addtoinbuf(d, (idata >> 8) & 0xff);                                  case 2: wdc_addtoinbuf(d, idata & 0xff);
650                                  break;                                          wdc_addtoinbuf(d, (idata >> 8) & 0xff);
651                          case 1: wdc_addtoinbuf(d, idata); break;                                          break;
652                          default:fatal("wdc: unimplemented write len %i\n", len);                                  case 1: wdc_addtoinbuf(d, idata); break;
653                                  exit(1);                                  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                          }                          }
673    
674                          inbuf_len = d->inbuf_head - d->inbuf_tail;                          inbuf_len = d->inbuf_head - d->inbuf_tail;
675                          while (inbuf_len < 0)                          while (inbuf_len < 0)
676                                  inbuf_len += WDC_INBUF_SIZE;                                  inbuf_len += WDC_INBUF_SIZE;
677    
678  #if 0                          if (d->atapi_cmd_in_progress && inbuf_len == 12) {
679                          if ((inbuf_len % (512 * d->write_count)) == 0) {                                  unsigned char *scsi_cmd = malloc(12);
680  #endif                                  int x = 0, res;
681                          if ((inbuf_len % 512) == 0) {  
682                                  int count = 1;  /*  d->write_count;  */                                  if (d->atapi_st != NULL)
683                                  unsigned char *buf = malloc(count * 512);                                          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                                    d->int_assert = 1;
736                            }
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                                    unsigned char *buf = malloc(512 * count);
746                                    unsigned char *b = buf;
747    
748                                  if (buf == NULL) {                                  if (buf == NULL) {
749                                          fprintf(stderr, "out of memory\n");                                          fprintf(stderr, "out of memory\n");
750                                          exit(1);                                          exit(1);
751                                  }                                  }
752    
753                                  for (i=0; i<512 * count; i++)                                  if (d->inbuf_tail+512*count <= WDC_INBUF_SIZE) {
754                                          buf[i] = wdc_get_inbuf(d);                                          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                                    }
761    
762                                  diskimage_access(cpu->machine,                                  diskimage_access(cpu->machine,
763                                      d->drive + d->base_drive, 1,                                      d->drive + d->base_drive, DISKIMAGE_IDE, 1,
764                                      d->write_offset, buf, 512 * count);                                      d->write_offset, b, 512 * count);
                                 free(buf);  
765    
766                                  d->write_count --;                                  d->write_count -= count;
767                                  d->write_offset += 512;                                  d->write_offset += 512 * count;
768    
769                                  d->delayed_interrupt = INT_DELAY;                                  d->int_assert = 1;
770    
771                                  if (d->write_count == 0)                                  if (d->write_count == 0)
772                                          d->write_in_progress = 0;                                          d->write_in_progress = 0;
773    
774                                    free(buf);
775                          }                          }
776                  }                  }
777                  break;                  break;
778    
779          case wd_error:  /*  1: error (r), precomp (w)  */          case wd_error:  /*  1: error (r), precomp (w)  */
780                  if (writeflag==MEM_READ) {                  if (writeflag == MEM_READ) {
781                          odata = d->error;                          odata = d->error;
782                          debug("[ wdc: read from ERROR: 0x%02x ]\n", odata);                          debug("[ wdc: read from ERROR: 0x%02x ]\n", (int)odata);
783                          /*  TODO:  is the error value cleared on read?  */                          /*  TODO:  is the error value cleared on read?  */
784                          d->error = 0;                          d->error = 0;
785                  } else {                  } else {
786                          d->precomp = idata;                          d->precomp = idata;
787                          debug("[ wdc: write to PRECOMP: 0x%02x ]\n", idata);                          debug("[ wdc: write to PRECOMP: 0x%02x ]\n",(int)idata);
788                  }                  }
789                  break;                  break;
790    
791          case wd_seccnt: /*  2: sector count  */          case wd_seccnt: /*  2: sector count (or "ireason" for ATAPI)  */
792                  if (writeflag==MEM_READ) {                  if (writeflag == MEM_READ) {
793                          odata = d->seccnt;                          odata = d->seccnt;
794                          debug("[ wdc: read from SECCNT: 0x%02x ]\n", odata);                          if (d->atapi_cmd_in_progress) {
795                                    odata = d->atapi_phase & (WDCI_CMD | WDCI_IN);
796                            }
797                            debug("[ wdc: read from SECCNT: 0x%02x ]\n",(int)odata);
798                  } else {                  } else {
799                          d->seccnt = idata;                          d->seccnt = idata;
800                          debug("[ wdc: write to SECCNT: 0x%02x ]\n", idata);                          debug("[ wdc: write to SECCNT: 0x%02x ]\n", (int)idata);
801                  }                  }
802                  break;                  break;
803    
804          case wd_sector: /*  3: first sector  */          case wd_sector: /*  3: first sector  */
805                  if (writeflag==MEM_READ) {                  if (writeflag == MEM_READ) {
806                          odata = d->sector;                          odata = d->sector;
807                          debug("[ wdc: read from SECTOR: 0x%02x ]\n", odata);                          debug("[ wdc: read from SECTOR: 0x%02x ]\n",(int)odata);
808                  } else {                  } else {
809                          d->sector = idata;                          d->sector = idata;
810                          debug("[ wdc: write to SECTOR: 0x%02x ]\n", idata);                          debug("[ wdc: write to SECTOR: 0x%02x ]\n", (int)idata);
811                  }                  }
812                  break;                  break;
813    
814          case wd_cyl_lo: /*  4: cylinder low  */          case wd_cyl_lo: /*  4: cylinder low  */
815                  if (writeflag==MEM_READ) {                  if (writeflag == MEM_READ) {
816                          odata = d->cyl_lo;                          odata = d->cyl_lo;
817                          debug("[ wdc: read from CYL_LO: 0x%02x ]\n", odata);                          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                            debug("[ wdc: read from CYL_LO: 0x%02x ]\n",(int)odata);
828                  } else {                  } else {
829                          d->cyl_lo = idata;                          d->cyl_lo = idata;
830                          debug("[ wdc: write to CYL_LO: 0x%02x ]\n", idata);                          debug("[ wdc: write to CYL_LO: 0x%02x ]\n", (int)idata);
831                  }                  }
832                  break;                  break;
833    
834          case wd_cyl_hi: /*  5: cylinder low  */          case wd_cyl_hi: /*  5: cylinder high  */
835                  if (writeflag==MEM_READ) {                  if (writeflag == MEM_READ) {
836                          odata = d->cyl_hi;                          odata = d->cyl_hi;
837                          debug("[ wdc: read from CYL_HI: 0x%02x ]\n", odata);                          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                            debug("[ wdc: read from CYL_HI: 0x%02x ]\n",(int)odata);
848                  } else {                  } else {
849                          d->cyl_hi = idata;                          d->cyl_hi = idata;
850                          debug("[ wdc: write to CYL_HI: 0x%02x ]\n", idata);                          debug("[ wdc: write to CYL_HI: 0x%02x ]\n", (int)idata);
851                  }                  }
852                  break;                  break;
853    
# Line 429  int dev_wdc_access(struct cpu *cpu, stru Line 872  int dev_wdc_access(struct cpu *cpu, stru
872          case wd_command:        /*  7: command or status  */          case wd_command:        /*  7: command or status  */
873                  if (writeflag==MEM_READ) {                  if (writeflag==MEM_READ) {
874                          odata = status_byte(d, cpu);                          odata = status_byte(d, cpu);
875  #if 1                          if (!quiet_mode)
876                          debug("[ wdc: read from STATUS: 0x%02x ]\n", odata);                                  debug("[ wdc: read from STATUS: 0x%02x ]\n",
877  #endif                                      (int)odata);
878                            INTERRUPT_DEASSERT(d->irq);
879                          cpu_interrupt_ack(cpu, d->irq_nr);                          d->int_assert = 0;
                         d->delayed_interrupt = 0;  
880                  } else {                  } else {
881                          debug("[ wdc: write to COMMAND: 0x%02x ]\n", idata);                          debug("[ wdc: write to COMMAND: 0x%02x ]\n",(int)idata);
882                          d->cur_command = idata;                          wdc_command(cpu, d, idata);
   
                         /*  TODO:  Is this correct behaviour?  */  
                         if (!diskimage_exist(cpu->machine,  
                             d->drive + d->base_drive)) {  
                                 d->error |= WDCE_ABRT;  
                                 d->delayed_interrupt = INT_DELAY;  
                                 break;  
                         }  
   
                         /*  Handle the command:  */  
                         switch (d->cur_command) {  
                         case WDCC_READ:  
                                 debug("[ wdc: READ from drive %i, head %i, "  
                                     "cylinder %i, sector %i, nsecs %i ]\n",  
                                     d->drive, d->head, d->cyl_hi*256+d->cyl_lo,  
                                     d->sector, d->seccnt);  
                                 /*  TODO:  HAHA! This should be removed  
                                     quickly  */  
                                 {  
                                         unsigned char buf[512*256];  
                                         int cyl = d->cyl_hi * 256+ d->cyl_lo;  
                                         int count = d->seccnt? d->seccnt : 256;  
                                         uint64_t offset = 512 * (d->sector - 1  
                                             + d->head * 63 + 16*63*cyl);  
   
 #if 0  
 /*  LBA:  */  
 if (d->lba)  
         offset = 512 * (((d->head & 0xf) << 24) + (cyl << 8) + d->sector);  
 printf("WDC read from offset %lli\n", (long long)offset);  
 #endif  
                                         diskimage_access(cpu->machine,  
                                             d->drive + d->base_drive, 0,  
                                             offset, buf, 512 * count);  
                                         /*  TODO: result code  */  
                                         for (i=0; i<512 * count; i++)  
                                                 wdc_addtoinbuf(d, buf[i]);  
                                 }  
                                 d->delayed_interrupt = INT_DELAY;  
                                 break;  
                         case WDCC_WRITE:  
                                 debug("[ wdc: WRITE to drive %i, head %i, "  
                                     "cylinder %i, sector %i, nsecs %i ]\n",  
                                     d->drive, d->head, d->cyl_hi*256+d->cyl_lo,  
                                     d->sector, d->seccnt);  
                                 /*  TODO:  HAHA! This should be removed  
                                     quickly  */  
                                 {  
                                         int cyl = d->cyl_hi * 256+ d->cyl_lo;  
                                         int count = d->seccnt? d->seccnt : 256;  
                                         uint64_t offset = 512 * (d->sector - 1  
                                             + d->head * 63 + 16*63*cyl);  
   
 #if 0  
 /*  LBA:  */  
 if (d->lba)  
         offset = 512 * (((d->head & 0xf) << 24) + (cyl << 8) + d->sector);  
 printf("WDC write to offset %lli\n", (long long)offset);  
 #endif  
   
                                         d->write_in_progress = 1;  
                                         d->write_count = count;  
                                         d->write_offset = offset;  
   
                                         /*  TODO: result code  */  
                                 }  
 /*  TODO: Really interrupt here?  */  
 #if 0  
                                 d->delayed_interrupt = INT_DELAY;  
 #endif  
                                 break;  
   
                         case WDCC_IDP:  /*  Initialize drive parameters  */  
                                 debug("[ wdc: IDP drive %i (TODO) ]\n",  
                                     d->drive);  
                                 /*  TODO  */  
                                 d->delayed_interrupt = INT_DELAY;  
                                 break;  
                         case SET_FEATURES:  
                                 fatal("[ wdc: SET_FEATURES drive %i (TODO), "  
                                     "feature 0x%02x ]\n", d->drive, d->precomp);  
                                 /*  TODO  */  
                                 switch (d->precomp) {  
                                 case WDSF_SET_MODE:  
                                         fatal("[ wdc: WDSF_SET_MODE drive %i, "  
                                             "pio/dma flags 0x%02x ]\n",  
                                             d->drive, d->seccnt);  
                                         break;  
                                 default:  
                                         d->error |= WDCE_ABRT;  
                                 }  
                                 /*  TODO: always interrupt?  */  
                                 d->delayed_interrupt = INT_DELAY;  
                                 break;  
                         case WDCC_RECAL:  
                                 debug("[ wdc: RECAL drive %i ]\n", d->drive);  
                                 d->delayed_interrupt = INT_DELAY;  
                                 break;  
                         case WDCC_IDENTIFY:  
                                 debug("[ wdc: IDENTIFY drive %i ]\n", d->drive);  
                                 wdc_initialize_identify_struct(cpu, d);  
                                 /*  The IDENTIFY data block is sent out  
                                     in low/high byte order:  */  
                                 for (i=0; i<sizeof(d->identify_struct); i+=2) {  
                                         wdc_addtoinbuf(d, d->identify_struct  
                                             [i+1]);  
                                         wdc_addtoinbuf(d, d->identify_struct  
                                             [i+0]);  
                                 }  
                                 d->delayed_interrupt = INT_DELAY;  
                                 break;  
                         case WDCC_IDLE_IMMED:  
                                 debug("[ wdc: IDLE_IMMED drive %i ]\n",  
                                     d->drive);  
                                 /*  TODO: interrupt here?  */  
                                 d->delayed_interrupt = INT_DELAY;  
                                 break;  
                         default:  
                                 /*  TODO  */  
                                 d->error |= WDCE_ABRT;  
   
                                 fatal("[ wdc: unknown command 0x%02x ("  
                                     "drive %i, head %i, cylinder %i, sector %i,"  
                                     " nsecs %i) ]\n", d->cur_command, d->drive,  
                                     d->head, d->cyl_hi*256+d->cyl_lo,  
                                     d->sector, d->seccnt);  
                                 exit(1);  
                         }  
883                  }                  }
884                  break;                  break;
885    
# Line 578  printf("WDC write to offset %lli\n", (lo Line 892  printf("WDC write to offset %lli\n", (lo
892                              (int)relative_addr, (int)idata);                              (int)relative_addr, (int)idata);
893          }          }
894    
895          if (writeflag == MEM_READ)          /*  Assert interrupt, if necessary:  */
896                  memory_writemax64(cpu, data, len, odata);          dev_wdc_tick(cpu, extra);
897    
898    ret:
899            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          return 1;          return 1;
907  }  }
908    
909    
910  /*  DEVINIT(wdc)
  *  dev_wdc_init():  
  *  
  *  base_drive should be 0 for the primary device, and 2 for the secondary.  
  */  
 void dev_wdc_init(struct machine *machine, struct memory *mem,  
         uint64_t baseaddr, int irq_nr, int base_drive)  
911  {  {
912          struct wdc_data *d;          struct wdc_data *d;
913          uint64_t alt_status_addr;          uint64_t alt_status_addr;
914            int i, tick_shift = WDC_TICK_SHIFT;
915    
916          d = malloc(sizeof(struct wdc_data));          d = malloc(sizeof(struct wdc_data));
917          if (d == NULL) {          if (d == NULL) {
# Line 602  void dev_wdc_init(struct machine *machin Line 919  void dev_wdc_init(struct machine *machin
919                  exit(1);                  exit(1);
920          }          }
921          memset(d, 0, sizeof(struct wdc_data));          memset(d, 0, sizeof(struct wdc_data));
         d->irq_nr     = irq_nr;  
         d->base_drive = base_drive;  
922    
923          alt_status_addr = baseaddr + 0x206;          INTERRUPT_CONNECT(devinit->interrupt_path, d->irq);
924            d->addr_mult  = devinit->addr_mult;
925            d->data_debug = 1;
926            d->io_enabled = 1;
927    
928            d->inbuf = zeroed_alloc(WDC_INBUF_SIZE);
929    
930            /*  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    
935            alt_status_addr = devinit->addr + 0x206;
936    
937            /*  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    
952            /*  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    
960            memory_device_register(devinit->machine->memory, "wdc_altstatus",
961                alt_status_addr, 2, dev_wdc_altstatus_access, d, DM_DEFAULT, NULL);
962            memory_device_register(devinit->machine->memory, devinit->name,
963                devinit->addr, DEV_WDC_LENGTH * devinit->addr_mult, dev_wdc_access,
964                d, DM_DEFAULT, NULL);
965    
966            machine_add_tickfunction(devinit->machine, dev_wdc_tick,
967                d, tick_shift, 0.0);
968    
969          /*  Special hack for pcic/hpcmips:  TODO: Fix  */          devinit->return_ptr = d;
         if (baseaddr == 0x14000180)  
                 alt_status_addr = 0x14000386;  
   
         memory_device_register(mem, "wdc_altstatus", alt_status_addr, 2,  
             dev_wdc_altstatus_access, d, MEM_DEFAULT, NULL);  
         memory_device_register(mem, "wdc", baseaddr, DEV_WDC_LENGTH,  
             dev_wdc_access, d, MEM_DEFAULT, NULL);  
970    
971          machine_add_tickfunction(machine, dev_wdc_tick,          return 1;
             d, WDC_TICK_SHIFT);  
972  }  }
973    

Legend:
Removed from v.4  
changed lines
  Added in v.34

  ViewVC Help
Powered by ViewVC 1.1.26