/[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 6 by dpavlin, Mon Oct 8 16:18:11 2007 UTC revision 18 by dpavlin, Mon Oct 8 16:19:11 2007 UTC
# 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.37 2005/05/27 07:29:25 debug Exp $   *
28   *     *  $Id: dev_wdc.c,v 1.44 2005/10/26 14:37:05 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.  */  /*
52     *  INT_DELAY: This is an old hack which only exists because (some versions of)
53     *  NetBSD for hpcmips have interrupt problems. These problems are probably not
54     *  specific to GXemul, but are also triggered on real hardware.
55     *
56     *  See the following URL for more info:
57     *  http://mail-index.netbsd.org/port-hpcmips/2004/12/30/0003.html
58     */
59  #define INT_DELAY               1  #define INT_DELAY               1
60    
61  extern int quiet_mode;  extern int quiet_mode;
62    
63  /*  #define debug fatal  */  /*  #define debug fatal  */
 /*  #define DATA_DEBUG  */  
64    
65  struct wdc_data {  struct wdc_data {
66          int             irq_nr;          int             irq_nr;
67          int             base_drive;          int             base_drive;
68            int             data_debug;
69    
70          int             delayed_interrupt;          /*  Cached values:  */
71            int             cyls[2];
72            int             heads[2];
73            int             sectors_per_track[2];
74    
75          unsigned char   identify_struct[512];          unsigned char   identify_struct[512];
76    
# Line 69  struct wdc_data { Line 78  struct wdc_data {
78          int             inbuf_head;          int             inbuf_head;
79          int             inbuf_tail;          int             inbuf_tail;
80    
81            int             delayed_interrupt;
82          int             write_in_progress;          int             write_in_progress;
83          int             write_count;          int             write_count;
84          int64_t         write_offset;          int64_t         write_offset;
# Line 114  static void wdc_addtoinbuf(struct wdc_da Line 124  static void wdc_addtoinbuf(struct wdc_da
124    
125          d->inbuf_head = (d->inbuf_head + 1) % WDC_INBUF_SIZE;          d->inbuf_head = (d->inbuf_head + 1) % WDC_INBUF_SIZE;
126          if (d->inbuf_head == d->inbuf_tail)          if (d->inbuf_head == d->inbuf_tail)
127                  fatal("[ wdc_addtoinbuf(): WARNING! wdc inbuf overrun ]\n");                  fatal("[ wdc_addtoinbuf(): WARNING! wdc inbuf overrun!"
128                        " Increase WDC_MAX_SECTORS. ]\n");
129  }  }
130    
131    
# Line 144  static uint64_t wdc_get_inbuf(struct wdc Line 155  static uint64_t wdc_get_inbuf(struct wdc
155  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)
156  {  {
157          uint64_t total_size;          uint64_t total_size;
158          int cyls, heads, sectors_per_track;          char namebuf[40];
159    
160          total_size = diskimage_getsize(cpu->machine, d->drive + d->base_drive,          total_size = diskimage_getsize(cpu->machine, d->drive + d->base_drive,
161              DISKIMAGE_IDE);              DISKIMAGE_IDE);
162    
         diskimage_getchs(cpu->machine, d->drive + d->base_drive,  
             DISKIMAGE_IDE, &cyls, &heads, &sectors_per_track);  
   
163          memset(d->identify_struct, 0, sizeof(d->identify_struct));          memset(d->identify_struct, 0, sizeof(d->identify_struct));
164    
165          /*  Offsets are in 16-bit WORDS!  High byte, then low.  */          /*  Offsets are in 16-bit WORDS!  High byte, then low.  */
# Line 161  static void wdc_initialize_identify_stru Line 169  static void wdc_initialize_identify_stru
169          d->identify_struct[2 * 0 + 1] = 1 << 6;          d->identify_struct[2 * 0 + 1] = 1 << 6;
170    
171          /*  1: nr of cylinders  */          /*  1: nr of cylinders  */
172          d->identify_struct[2 * 1 + 0] = (cyls >> 8);          d->identify_struct[2 * 1 + 0] = (d->cyls[d->drive] >> 8);
173          d->identify_struct[2 * 1 + 1] = cyls & 255;          d->identify_struct[2 * 1 + 1] = d->cyls[d->drive] & 255;
174    
175          /*  3: nr of heads  */          /*  3: nr of heads  */
176          d->identify_struct[2 * 3 + 0] = heads >> 8;          d->identify_struct[2 * 3 + 0] = d->heads[d->drive] >> 8;
177          d->identify_struct[2 * 3 + 1] = heads;          d->identify_struct[2 * 3 + 1] = d->heads[d->drive];
178    
179          /*  6: sectors per track  */          /*  6: sectors per track  */
180          d->identify_struct[2 * 6 + 0] = sectors_per_track >> 8;          d->identify_struct[2 * 6 + 0] = d->sectors_per_track[d->drive] >> 8;
181          d->identify_struct[2 * 6 + 1] = sectors_per_track;          d->identify_struct[2 * 6 + 1] = d->sectors_per_track[d->drive];
182    
183          /*  10-19: Serial number  */          /*  10-19: Serial number  */
184          memcpy(&d->identify_struct[2 * 10], "S/N 1234-5678       ", 20);          memcpy(&d->identify_struct[2 * 10], "S/N 1234-5678       ", 20);
# Line 179  static void wdc_initialize_identify_stru Line 187  static void wdc_initialize_identify_stru
187          memcpy(&d->identify_struct[2 * 23], "VER 1.0 ", 8);          memcpy(&d->identify_struct[2 * 23], "VER 1.0 ", 8);
188    
189          /*  27-46: Model number  */          /*  27-46: Model number  */
190          memcpy(&d->identify_struct[2 * 27],          if (diskimage_getname(cpu->machine, d->drive + d->base_drive,
191              "Fake GXemul IDE disk                    ", 40);              DISKIMAGE_IDE, namebuf, sizeof(namebuf))) {
192          /*  TODO:  Use the diskimage's filename instead?  */                  int i;
193                    for (i=0; i<sizeof(namebuf); i++)
194                            if (namebuf[i] == 0) {
195                                    for (; i<sizeof(namebuf); i++)
196                                            namebuf[i] = ' ';
197                                    break;
198                            }
199                    memcpy(&d->identify_struct[2 * 27], namebuf, 40);
200            } else
201                    memcpy(&d->identify_struct[2 * 27],
202                        "Fake GXemul IDE disk                    ", 40);
203    
204          /*  47: max sectors per multitransfer  */          /*  47: max sectors per multitransfer  */
205          d->identify_struct[2 * 47 + 0] = 0x80;          d->identify_struct[2 * 47 + 0] = 0x80;
# Line 203  static void wdc_initialize_identify_stru Line 221  static void wdc_initialize_identify_stru
221    
222    
223  /*  /*
224     *  wdc__read():
225     */
226    void wdc__read(struct cpu *cpu, struct wdc_data *d)
227    {
228            const int max_sectors_per_chunk = 64;
229            unsigned char buf[512 * max_sectors_per_chunk];
230            int i, cyl = d->cyl_hi * 256+ d->cyl_lo;
231            int count = d->seccnt? d->seccnt : 256;
232            uint64_t offset = 512 * (d->sector - 1
233                + d->head * d->sectors_per_track[d->drive] +
234                d->heads[d->drive] * d->sectors_per_track[d->drive] * cyl);
235    
236    #if 0
237            /*  LBA:  */
238            if (d->lba)
239                    offset = 512 * (((d->head & 0xf) << 24) + (cyl << 8)
240                        + d->sector);
241            printf("WDC read from offset %lli\n", (long long)offset);
242    #endif
243    
244            while (count > 0) {
245                    int to_read = count > max_sectors_per_chunk?
246                        max_sectors_per_chunk : count;
247    
248                    /*  TODO: result code from the read?  */
249    
250                    if (d->inbuf_head + 512 * to_read <= WDC_INBUF_SIZE) {
251                            diskimage_access(cpu->machine, d->drive + d->base_drive,
252                                DISKIMAGE_IDE, 0, offset,
253                                d->inbuf + d->inbuf_head, 512 * to_read);
254                            d->inbuf_head += 512 * to_read;
255                            if (d->inbuf_head == WDC_INBUF_SIZE)
256                                    d->inbuf_head = 0;
257                    } else {
258                            diskimage_access(cpu->machine, d->drive + d->base_drive,
259                                DISKIMAGE_IDE, 0, offset, buf, 512 * to_read);
260                            for (i=0; i<512 * to_read; i++)
261                                    wdc_addtoinbuf(d, buf[i]);
262                    }
263    
264                    offset += 512 * to_read;
265                    count -= to_read;
266            }
267    
268            d->delayed_interrupt = INT_DELAY;
269    }
270    
271    
272    /*
273     *  wdc__write():
274     */
275    void wdc__write(struct cpu *cpu, struct wdc_data *d)
276    {
277            int cyl = d->cyl_hi * 256+ d->cyl_lo;
278            int count = d->seccnt? d->seccnt : 256;
279            uint64_t offset = 512 * (d->sector - 1
280                + d->head * d->sectors_per_track[d->drive] +
281                d->heads[d->drive] * d->sectors_per_track[d->drive] * cyl);
282    #if 0
283            /*  LBA:  */
284            if (d->lba)
285                    offset = 512 * (((d->head & 0xf) << 24) +
286                        (cyl << 8) + d->sector);
287            printf("WDC write to offset %lli\n", (long long)offset);
288    #endif
289    
290            d->write_in_progress = 1;
291            d->write_count = count;
292            d->write_offset = offset;
293    
294            /*  TODO: result code?  */
295    }
296    
297    
298    /*
299   *  status_byte():   *  status_byte():
300     *
301     *  Return a reasonable status byte corresponding to the controller's current
302     *  state.
303   */   */
304  static int status_byte(struct wdc_data *d, struct cpu *cpu)  static int status_byte(struct wdc_data *d, struct cpu *cpu)
305  {  {
306          int odata = 0;          int odata = 0;
307    
308            /*
309             *  Modern versions of OpenBSD wants WDCS_DSC. (Thanks to Alexander
310             *  Yurchenko for noticing this.)
311             */
312          if (diskimage_exist(cpu->machine, d->drive + d->base_drive,          if (diskimage_exist(cpu->machine, d->drive + d->base_drive,
313              DISKIMAGE_IDE))              DISKIMAGE_IDE))
314                  odata |= WDCS_DRDY;                  odata |= WDCS_DRDY | WDCS_DSC;
315          if (d->inbuf_head != d->inbuf_tail)          if (d->inbuf_head != d->inbuf_tail)
316                  odata |= WDCS_DRQ;                  odata |= WDCS_DRQ;
317          if (d->write_in_progress)          if (d->write_in_progress)
# Line 219  static int status_byte(struct wdc_data * Line 319  static int status_byte(struct wdc_data *
319          if (d->error)          if (d->error)
320                  odata |= WDCS_ERR;                  odata |= WDCS_ERR;
321    
 #if 0  
         /*  
          *  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,  
             DISKIMAGE_IDE))  
                 odata = 0xff;  
 #endif  
   
322          return odata;          return odata;
323  }  }
324    
# Line 244  int dev_wdc_altstatus_access(struct cpu Line 333  int dev_wdc_altstatus_access(struct cpu
333          struct wdc_data *d = extra;          struct wdc_data *d = extra;
334          uint64_t idata = 0, odata = 0;          uint64_t idata = 0, odata = 0;
335    
336          idata = memory_readmax64(cpu, data, len);          idata = data[0];
337    
338          /*  Same as the normal status byte?  */          /*  Same as the normal status byte?  */
339          odata = status_byte(d, cpu);          odata = status_byte(d, cpu);
# Line 257  int dev_wdc_altstatus_access(struct cpu Line 346  int dev_wdc_altstatus_access(struct cpu
346                      (int)idata);                      (int)idata);
347    
348          if (writeflag == MEM_READ)          if (writeflag == MEM_READ)
349                  memory_writemax64(cpu, data, len, odata);                  data[0] = odata;
350    
351          return 1;          return 1;
352  }  }
# Line 272  int dev_wdc_access(struct cpu *cpu, stru Line 361  int dev_wdc_access(struct cpu *cpu, stru
361  {  {
362          struct wdc_data *d = extra;          struct wdc_data *d = extra;
363          uint64_t idata = 0, odata = 0;          uint64_t idata = 0, odata = 0;
364          int i, cyls, heads, sectors_per_track;          int i;
365    
366          idata = memory_readmax64(cpu, data, len);          if (writeflag == MEM_WRITE) {
367                    if (relative_addr == wd_data)
368                            idata = memory_readmax64(cpu, data, len);
369                    else
370                            idata = data[0];
371            }
372    
373          switch (relative_addr) {          switch (relative_addr) {
374    
375          case wd_data:   /*  0: data  */          case wd_data:   /*  0: data  */
376                  if (writeflag==MEM_READ) {                  if (writeflag == MEM_READ) {
377                          odata = 0;                          odata = 0;
378    
379                          /*  TODO: This is hardcoded for little-endian?  */                          /*  TODO: This is hardcoded for little-endian?  */
# Line 292  int dev_wdc_access(struct cpu *cpu, stru Line 386  int dev_wdc_access(struct cpu *cpu, stru
386                                  odata += (wdc_get_inbuf(d) << 24);                                  odata += (wdc_get_inbuf(d) << 24);
387                          }                          }
388    
389  #ifdef DATA_DEBUG                          if (d->data_debug)
390                          debug("[ wdc: read from DATA: 0x%04x ]\n", odata);                                  debug("[ wdc: read from DATA: 0x%04x ]\n",
391  #endif                                      (int)odata);
392    #if 0
393                          if (d->inbuf_tail != d->inbuf_head)                          if (d->inbuf_tail != d->inbuf_head)
394    #else
395                            if (d->inbuf_tail != d->inbuf_head &&
396                                ((d->inbuf_tail - d->inbuf_head) % 512) == 0)
397    #endif
398                                  d->delayed_interrupt = INT_DELAY;                                  d->delayed_interrupt = INT_DELAY;
   
399                  } else {                  } else {
400                          int inbuf_len;                          int inbuf_len;
401  #ifdef DATA_DEBUG                          if (d->data_debug)
402                          debug("[ wdc: write to DATA (len=%i): 0x%08lx ]\n",                                  debug("[ wdc: write to DATA (len=%i): "
403                              (int)len, (long)idata);                                      "0x%08lx ]\n", (int)len, (long)idata);
 #endif  
404                          if (!d->write_in_progress) {                          if (!d->write_in_progress) {
405                                  fatal("[ wdc: write to DATA, but not "                                  fatal("[ wdc: write to DATA, but not "
406                                      "expecting any? (len=%i): 0x%08lx ]\n",                                      "expecting any? (len=%i): 0x%08lx ]\n",
# Line 331  int dev_wdc_access(struct cpu *cpu, stru Line 427  int dev_wdc_access(struct cpu *cpu, stru
427    
428  #if 0  #if 0
429                          if ((inbuf_len % (512 * d->write_count)) == 0) {                          if ((inbuf_len % (512 * d->write_count)) == 0) {
430  #endif  #else
431                          if ((inbuf_len % 512) == 0) {                          if ((inbuf_len % 512) == 0) {
432    #endif
433                                  int count = 1;  /*  d->write_count;  */                                  int count = 1;  /*  d->write_count;  */
434                                  unsigned char *buf = malloc(count * 512);                                  unsigned char buf[512 * count];
435                                  if (buf == NULL) {                                  unsigned char *b = buf;
                                         fprintf(stderr, "out of memory\n");  
                                         exit(1);  
                                 }  
436    
437                                  for (i=0; i<512 * count; i++)                                  if (d->inbuf_tail+512*count <= WDC_INBUF_SIZE) {
438                                          buf[i] = wdc_get_inbuf(d);                                          b = d->inbuf + d->inbuf_tail;
439                                            d->inbuf_tail = (d->inbuf_tail + 512
440                                                * count) % WDC_INBUF_SIZE;
441                                    } else {
442                                            for (i=0; i<512 * count; i++)
443                                                    buf[i] = wdc_get_inbuf(d);
444                                    }
445    
446                                  diskimage_access(cpu->machine,                                  diskimage_access(cpu->machine,
447                                      d->drive + d->base_drive, DISKIMAGE_IDE, 1,                                      d->drive + d->base_drive, DISKIMAGE_IDE, 1,
448                                      d->write_offset, buf, 512 * count);                                      d->write_offset, b, 512 * count);
                                 free(buf);  
449    
450                                  d->write_count --;                                  d->write_count --;
451                                  d->write_offset += 512;                                  d->write_offset += 512;
# Line 362  int dev_wdc_access(struct cpu *cpu, stru Line 461  int dev_wdc_access(struct cpu *cpu, stru
461          case wd_error:  /*  1: error (r), precomp (w)  */          case wd_error:  /*  1: error (r), precomp (w)  */
462                  if (writeflag==MEM_READ) {                  if (writeflag==MEM_READ) {
463                          odata = d->error;                          odata = d->error;
464                          debug("[ wdc: read from ERROR: 0x%02x ]\n", odata);                          debug("[ wdc: read from ERROR: 0x%02x ]\n",
465                                (int)odata);
466                          /*  TODO:  is the error value cleared on read?  */                          /*  TODO:  is the error value cleared on read?  */
467                          d->error = 0;                          d->error = 0;
468                  } else {                  } else {
469                          d->precomp = idata;                          d->precomp = idata;
470                          debug("[ wdc: write to PRECOMP: 0x%02x ]\n", idata);                          debug("[ wdc: write to PRECOMP: 0x%02x ]\n",(int)idata);
471                  }                  }
472                  break;                  break;
473    
474          case wd_seccnt: /*  2: sector count  */          case wd_seccnt: /*  2: sector count  */
475                  if (writeflag==MEM_READ) {                  if (writeflag==MEM_READ) {
476                          odata = d->seccnt;                          odata = d->seccnt;
477                          debug("[ wdc: read from SECCNT: 0x%02x ]\n", odata);                          debug("[ wdc: read from SECCNT: 0x%02x ]\n",(int)odata);
478                  } else {                  } else {
479                          d->seccnt = idata;                          d->seccnt = idata;
480                          debug("[ wdc: write to SECCNT: 0x%02x ]\n", idata);                          debug("[ wdc: write to SECCNT: 0x%02x ]\n", (int)idata);
481                  }                  }
482                  break;                  break;
483    
484          case wd_sector: /*  3: first sector  */          case wd_sector: /*  3: first sector  */
485                  if (writeflag==MEM_READ) {                  if (writeflag==MEM_READ) {
486                          odata = d->sector;                          odata = d->sector;
487                          debug("[ wdc: read from SECTOR: 0x%02x ]\n", odata);                          debug("[ wdc: read from SECTOR: 0x%02x ]\n",(int)odata);
488                  } else {                  } else {
489                          d->sector = idata;                          d->sector = idata;
490                          debug("[ wdc: write to SECTOR: 0x%02x ]\n", idata);                          debug("[ wdc: write to SECTOR: 0x%02x ]\n", (int)idata);
491                  }                  }
492                  break;                  break;
493    
494          case wd_cyl_lo: /*  4: cylinder low  */          case wd_cyl_lo: /*  4: cylinder low  */
495                  if (writeflag==MEM_READ) {                  if (writeflag==MEM_READ) {
496                          odata = d->cyl_lo;                          odata = d->cyl_lo;
497                          debug("[ wdc: read from CYL_LO: 0x%02x ]\n", odata);                          debug("[ wdc: read from CYL_LO: 0x%02x ]\n",(int)odata);
498                  } else {                  } else {
499                          d->cyl_lo = idata;                          d->cyl_lo = idata;
500                          debug("[ wdc: write to CYL_LO: 0x%02x ]\n", idata);                          debug("[ wdc: write to CYL_LO: 0x%02x ]\n", (int)idata);
501                  }                  }
502                  break;                  break;
503    
504          case wd_cyl_hi: /*  5: cylinder low  */          case wd_cyl_hi: /*  5: cylinder low  */
505                  if (writeflag==MEM_READ) {                  if (writeflag==MEM_READ) {
506                          odata = d->cyl_hi;                          odata = d->cyl_hi;
507                          debug("[ wdc: read from CYL_HI: 0x%02x ]\n", odata);                          debug("[ wdc: read from CYL_HI: 0x%02x ]\n",(int)odata);
508                  } else {                  } else {
509                          d->cyl_hi = idata;                          d->cyl_hi = idata;
510                          debug("[ wdc: write to CYL_HI: 0x%02x ]\n", idata);                          debug("[ wdc: write to CYL_HI: 0x%02x ]\n", (int)idata);
511                  }                  }
512                  break;                  break;
513    
# Line 432  int dev_wdc_access(struct cpu *cpu, stru Line 532  int dev_wdc_access(struct cpu *cpu, stru
532          case wd_command:        /*  7: command or status  */          case wd_command:        /*  7: command or status  */
533                  if (writeflag==MEM_READ) {                  if (writeflag==MEM_READ) {
534                          odata = status_byte(d, cpu);                          odata = status_byte(d, cpu);
 #if 1  
535                          if (!quiet_mode)                          if (!quiet_mode)
536                                  debug("[ wdc: read from STATUS: 0x%02x ]\n",                                  debug("[ wdc: read from STATUS: 0x%02x ]\n",
537                                      odata);                                      (int)odata);
 #endif  
   
538                          cpu_interrupt_ack(cpu, d->irq_nr);                          cpu_interrupt_ack(cpu, d->irq_nr);
539                          d->delayed_interrupt = 0;                          d->delayed_interrupt = 0;
540                  } else {                  } else {
541                          debug("[ wdc: write to COMMAND: 0x%02x ]\n", idata);                          debug("[ wdc: write to COMMAND: 0x%02x ]\n",(int)idata);
542                          d->cur_command = idata;                          d->cur_command = idata;
543    
544                          /*  TODO:  Is this correct behaviour?  */                          /*  TODO:  Is this correct behaviour?  */
# Line 454  int dev_wdc_access(struct cpu *cpu, stru Line 551  int dev_wdc_access(struct cpu *cpu, stru
551    
552                          /*  Handle the command:  */                          /*  Handle the command:  */
553                          switch (d->cur_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  */  
                                 diskimage_getchs(cpu->machine, d->drive +  
                                     d->base_drive, DISKIMAGE_IDE, &cyls,  
                                     &heads, &sectors_per_track);  
   
                                 {  
                                         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 * sectors_per_track +  
                                             heads*sectors_per_track*cyl);  
554    
555  #if 0                          case WDCC_READ:
556  /*  LBA:  */                                  if (!quiet_mode)
557  if (d->lba)                                          debug("[ wdc: READ from drive %i, head"
558          offset = 512 * (((d->head & 0xf) << 24) + (cyl << 8) + d->sector);                                              " %i, cyl %i, sector %i, nsecs %i "
559  printf("WDC read from offset %lli\n", (long long)offset);                                              "]\n", d->drive, d->head,
560  #endif                                              d->cyl_hi*256+d->cyl_lo, d->sector,
561                                          diskimage_access(cpu->machine,                                              d->seccnt);
562                                              d->drive + d->base_drive,                                  wdc__read(cpu, d);
                                             DISKIMAGE_IDE, 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;  
563                                  break;                                  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  */  
                                 diskimage_getchs(cpu->machine, d->drive +  
                                     d->base_drive, DISKIMAGE_IDE, &cyls,  
                                     &heads, &sectors_per_track);  
                                 {  
                                         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 * sectors_per_track +  
                                             heads*sectors_per_track*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  
564    
565                                          d->write_in_progress = 1;                          case WDCC_WRITE:
566                                          d->write_count = count;                                  if (!quiet_mode)
567                                          d->write_offset = offset;                                          debug("[ wdc: WRITE to drive %i, head"
568                                                " %i, cyl %i, sector %i, nsecs %i"
569                                          /*  TODO: result code  */                                              " ]\n", d->drive, d->head,
570                                  }                                              d->cyl_hi*256+d->cyl_lo, d->sector,
571  /*  TODO: Really interrupt here?  */                                              d->seccnt);
572  #if 0                                  wdc__write(cpu, d);
                                 d->delayed_interrupt = INT_DELAY;  
 #endif  
573                                  break;                                  break;
574    
575                          case WDCC_IDP:  /*  Initialize drive parameters  */                          case WDCC_IDP:  /*  Initialize drive parameters  */
# Line 531  printf("WDC write to offset %lli\n", (lo Line 578  printf("WDC write to offset %lli\n", (lo
578                                  /*  TODO  */                                  /*  TODO  */
579                                  d->delayed_interrupt = INT_DELAY;                                  d->delayed_interrupt = INT_DELAY;
580                                  break;                                  break;
581    
582                          case SET_FEATURES:                          case SET_FEATURES:
583                                  fatal("[ wdc: SET_FEATURES drive %i (TODO), "                                  fatal("[ wdc: SET_FEATURES drive %i (TODO), "
584                                      "feature 0x%02x ]\n", d->drive, d->precomp);                                      "feature 0x%02x ]\n", d->drive, d->precomp);
# Line 547  printf("WDC write to offset %lli\n", (lo Line 595  printf("WDC write to offset %lli\n", (lo
595                                  /*  TODO: always interrupt?  */                                  /*  TODO: always interrupt?  */
596                                  d->delayed_interrupt = INT_DELAY;                                  d->delayed_interrupt = INT_DELAY;
597                                  break;                                  break;
598    
599                          case WDCC_RECAL:                          case WDCC_RECAL:
600                                  debug("[ wdc: RECAL drive %i ]\n", d->drive);                                  debug("[ wdc: RECAL drive %i ]\n", d->drive);
601                                  d->delayed_interrupt = INT_DELAY;                                  d->delayed_interrupt = INT_DELAY;
602                                  break;                                  break;
603    
604                          case WDCC_IDENTIFY:                          case WDCC_IDENTIFY:
605                                  debug("[ wdc: IDENTIFY drive %i ]\n", d->drive);                                  debug("[ wdc: IDENTIFY drive %i ]\n", d->drive);
606                                  wdc_initialize_identify_struct(cpu, d);                                  wdc_initialize_identify_struct(cpu, d);
# Line 564  printf("WDC write to offset %lli\n", (lo Line 614  printf("WDC write to offset %lli\n", (lo
614                                  }                                  }
615                                  d->delayed_interrupt = INT_DELAY;                                  d->delayed_interrupt = INT_DELAY;
616                                  break;                                  break;
617    
618                          case WDCC_IDLE_IMMED:                          case WDCC_IDLE_IMMED:
619                                  debug("[ wdc: IDLE_IMMED drive %i ]\n",                                  debug("[ wdc: IDLE_IMMED drive %i ]\n",
620                                      d->drive);                                      d->drive);
621                                  /*  TODO: interrupt here?  */                                  /*  TODO: interrupt here?  */
622                                  d->delayed_interrupt = INT_DELAY;                                  d->delayed_interrupt = INT_DELAY;
623                                  break;                                  break;
624    
625                            /*  Unsupported commands, without warning:  */
626                            case ATAPI_IDENTIFY_DEVICE:
627                            case WDCC_SEC_SET_PASSWORD:
628                            case WDCC_SEC_UNLOCK:
629                            case WDCC_SEC_ERASE_PREPARE:
630                            case WDCC_SEC_ERASE_UNIT:
631                            case WDCC_SEC_FREEZE_LOCK:
632                            case WDCC_SEC_DISABLE_PASSWORD:
633                                    d->error |= WDCE_ABRT;
634                                    break;
635    
636                          default:                          default:
637                                  /*  TODO  */                                  /*  TODO  */
638                                  d->error |= WDCE_ABRT;                                  d->error |= WDCE_ABRT;
639    
640                                  fatal("[ wdc: unknown command 0x%02x ("                                  fatal("[ wdc: WARNING! Unimplemented command "
641                                      "drive %i, head %i, cylinder %i, sector %i,"                                      "0x%02x (drive %i, head %i, cyl %i, sector"
642                                      " nsecs %i) ]\n", d->cur_command, d->drive,                                      " %i, nsecs %i) ]\n", d->cur_command,
643                                      d->head, d->cyl_hi*256+d->cyl_lo,                                      d->drive, d->head, d->cyl_hi*256+d->cyl_lo,
644                                      d->sector, d->seccnt);                                      d->sector, d->seccnt);
                                 exit(1);  
645                          }                          }
646                  }                  }
647                  break;                  break;
# Line 593  printf("WDC write to offset %lli\n", (lo Line 655  printf("WDC write to offset %lli\n", (lo
655                              (int)relative_addr, (int)idata);                              (int)relative_addr, (int)idata);
656          }          }
657    
658          if (writeflag == MEM_READ)          if (cpu->machine->machine_type != MACHINE_HPCMIPS)
659                  memory_writemax64(cpu, data, len, odata);                  dev_wdc_tick(cpu, extra);
660    
661            if (writeflag == MEM_READ) {
662                    if (relative_addr == wd_data)
663                            memory_writemax64(cpu, data, len, odata);
664                    else
665                            data[0] = odata;
666            }
667    
668          return 1;          return 1;
669  }  }
670    
671    
672  /*  /*
673   *  dev_wdc_init():   *  devinit_wdc():
  *  
  *  base_drive should be 0 for the primary device, and 2 for the secondary.  
674   */   */
675  void dev_wdc_init(struct machine *machine, struct memory *mem,  int devinit_wdc(struct devinit *devinit)
         uint64_t baseaddr, int irq_nr, int base_drive)  
676  {  {
677          struct wdc_data *d;          struct wdc_data *d;
678          uint64_t alt_status_addr;          uint64_t alt_status_addr;
679            int i, tick_shift = WDC_TICK_SHIFT;
680    
681          d = malloc(sizeof(struct wdc_data));          d = malloc(sizeof(struct wdc_data));
682          if (d == NULL) {          if (d == NULL) {
# Line 617  void dev_wdc_init(struct machine *machin Line 684  void dev_wdc_init(struct machine *machin
684                  exit(1);                  exit(1);
685          }          }
686          memset(d, 0, sizeof(struct wdc_data));          memset(d, 0, sizeof(struct wdc_data));
687          d->irq_nr     = irq_nr;          d->irq_nr = devinit->irq_nr;
688          d->base_drive = base_drive;  
689            /*  base_drive = 0 for the primary controller, 2 for the secondary.  */
690            d->base_drive = 0;
691            if ((devinit->addr & 0xfff) == 0x170)
692                    d->base_drive = 2;
693    
694          alt_status_addr = baseaddr + 0x206;          alt_status_addr = devinit->addr + 0x206;
695    
696          /*  Special hack for pcic/hpcmips:  TODO: Fix  */          /*  Special hack for pcic/hpcmips:  TODO: Fix  */
697          if (baseaddr == 0x14000180)          if (devinit->addr == 0x14000180)
698                  alt_status_addr = 0x14000386;                  alt_status_addr = 0x14000386;
699    
700          memory_device_register(mem, "wdc_altstatus", alt_status_addr, 2,          /*  Get disk geometries:  */
701              dev_wdc_altstatus_access, d, MEM_DEFAULT, NULL);          for (i=0; i<2; i++)
702          memory_device_register(mem, "wdc", baseaddr, DEV_WDC_LENGTH,                  if (diskimage_exist(devinit->machine, d->base_drive +i,
703              dev_wdc_access, d, MEM_DEFAULT, NULL);                      DISKIMAGE_IDE))
704                            diskimage_getchs(devinit->machine, d->base_drive + i,
705                                DISKIMAGE_IDE, &d->cyls[i], &d->heads[i],
706                                &d->sectors_per_track[i]);
707    
708            memory_device_register(devinit->machine->memory, "wdc_altstatus",
709                alt_status_addr, 2, dev_wdc_altstatus_access, d, MEM_DEFAULT, NULL);
710            memory_device_register(devinit->machine->memory, devinit->name,
711                devinit->addr, DEV_WDC_LENGTH, dev_wdc_access, d, MEM_DEFAULT,
712                NULL);
713    
714          machine_add_tickfunction(machine, dev_wdc_tick,          if (devinit->machine->machine_type != MACHINE_HPCMIPS)
715              d, WDC_TICK_SHIFT);                  tick_shift += 2;
716    
717            machine_add_tickfunction(devinit->machine, dev_wdc_tick,
718                d, tick_shift);
719    
720            return 1;
721  }  }
722    

Legend:
Removed from v.6  
changed lines
  Added in v.18

  ViewVC Help
Powered by ViewVC 1.1.26