/[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 32 by dpavlin, Mon Oct 8 16:20:58 2007 UTC revision 34 by dpavlin, Mon Oct 8 16:21:17 2007 UTC
# Line 1  Line 1 
1  /*  /*
2   *  Copyright (C) 2004-2006  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 25  Line 25 
25   *  SUCH DAMAGE.   *  SUCH DAMAGE.
26   *   *
27   *   *
28   *  $Id: dev_wdc.c,v 1.69 2006/08/30 17:14:25 debug Exp $   *  $Id: dev_wdc.c,v 1.74 2007/02/16 19:57:56 debug Exp $
29   *   *
30   *  Standard "wdc" IDE controller.   *  Standard "wdc" IDE controller.
31   */   */
# Line 48  Line 48 
48  #define WDC_MAX_SECTORS         512  #define WDC_MAX_SECTORS         512
49  #define WDC_INBUF_SIZE          (512*(WDC_MAX_SECTORS+1))  #define WDC_INBUF_SIZE          (512*(WDC_MAX_SECTORS+1))
50    
 /*  
  *  INT_DELAY: This is an old hack which only exists because (some versions of)  
  *  NetBSD for hpcmips have interrupt problems. These problems are probably not  
  *  specific to GXemul, but are also triggered on real hardware.  
  *  
  *  See the following URL for more info:  
  *  http://mail-index.netbsd.org/port-hpcmips/2004/12/30/0003.html  
  *  
  *  NetBSD/malta also bugs out if wdc interrupts come too quickly. Hm.  
  */  
 #define INT_DELAY               1  
   
51  extern int quiet_mode;  extern int quiet_mode;
52    
53  /*  #define debug fatal  */  /*  #define debug fatal  */
54    
55  struct wdc_data {  struct wdc_data {
56          int             irq_nr;          struct interrupt irq;
57          int             addr_mult;          int             addr_mult;
58          int             base_drive;          int             base_drive;
59          int             data_debug;          int             data_debug;
# Line 80  struct wdc_data { Line 68  struct wdc_data {
68          int             inbuf_head;          int             inbuf_head;
69          int             inbuf_tail;          int             inbuf_tail;
70    
71          int             delayed_interrupt;          int             int_assert;
         int             int_asserted;  
72    
73          int             write_in_progress;          int             write_in_progress;
74          int             write_count;          int             write_count;
# Line 112  struct wdc_data { Line 99  struct wdc_data {
99  #define COMMAND_RESET   0x100  #define COMMAND_RESET   0x100
100    
101    
102  /*  DEVICE_TICK(wdc)
  *  dev_wdc_tick():  
  */  
 void dev_wdc_tick(struct cpu *cpu, void *extra)  
103  {  {
104          struct wdc_data *d = extra;          struct wdc_data *d = extra;
         int old_di = d->delayed_interrupt;  
   
         if (d->delayed_interrupt)  
                 d->delayed_interrupt --;  
105    
106          if (old_di == 1 || d->int_asserted) {          if (d->int_assert)
107                  cpu_interrupt(cpu, d->irq_nr);                  INTERRUPT_ASSERT(d->irq);
                 d->int_asserted = 1;  
         }  
108  }  }
109    
110    
# Line 329  void wdc__read(struct cpu *cpu, struct w Line 307  void wdc__read(struct cpu *cpu, struct w
307                  count -= to_read;                  count -= to_read;
308          }          }
309    
310          d->delayed_interrupt = INT_DELAY;          d->int_assert = 1;
311  }  }
312    
313    
# Line 384  static int status_byte(struct wdc_data * Line 362  static int status_byte(struct wdc_data *
362  }  }
363    
364    
 /*  
  *  dev_wdc_altstatus_access():  
  */  
365  DEVICE_ACCESS(wdc_altstatus)  DEVICE_ACCESS(wdc_altstatus)
366  {  {
367          struct wdc_data *d = extra;          struct wdc_data *d = extra;
# Line 437  void wdc_command(struct cpu *cpu, struct Line 412  void wdc_command(struct cpu *cpu, struct
412                  debug("[ wdc: command 0x%02x drive %i, but no disk image ]\n",                  debug("[ wdc: command 0x%02x drive %i, but no disk image ]\n",
413                      d->cur_command, d->drive + d->base_drive);                      d->cur_command, d->drive + d->base_drive);
414                  d->error |= WDCE_ABRT;                  d->error |= WDCE_ABRT;
415                  d->delayed_interrupt = INT_DELAY;                  d->int_assert = 1;
416                  return;                  return;
417          }          }
418          if (diskimage_is_a_cdrom(cpu->machine, d->drive + d->base_drive,          if (diskimage_is_a_cdrom(cpu->machine, d->drive + d->base_drive,
# Line 445  void wdc_command(struct cpu *cpu, struct Line 420  void wdc_command(struct cpu *cpu, struct
420                  debug("[ wdc: IDENTIFY drive %i, but it is an ATAPI "                  debug("[ wdc: IDENTIFY drive %i, but it is an ATAPI "
421                      "drive ]\n", d->drive + d->base_drive);                      "drive ]\n", d->drive + d->base_drive);
422                  d->error |= WDCE_ABRT;                  d->error |= WDCE_ABRT;
423                  d->delayed_interrupt = INT_DELAY;                  d->int_assert = 1;
424                  return;                  return;
425          }          }
426    
# Line 473  void wdc_command(struct cpu *cpu, struct Line 448  void wdc_command(struct cpu *cpu, struct
448          case WDCC_IDP:  /*  Initialize drive parameters  */          case WDCC_IDP:  /*  Initialize drive parameters  */
449                  debug("[ wdc: IDP drive %i (TODO) ]\n", d->drive);                  debug("[ wdc: IDP drive %i (TODO) ]\n", d->drive);
450                  /*  TODO  */                  /*  TODO  */
451                  d->delayed_interrupt = INT_DELAY;                  d->int_assert = 1;
452                  break;                  break;
453    
454          case SET_FEATURES:          case SET_FEATURES:
# Line 488  void wdc_command(struct cpu *cpu, struct Line 463  void wdc_command(struct cpu *cpu, struct
463                  default:d->error |= WDCE_ABRT;                  default:d->error |= WDCE_ABRT;
464                  }                  }
465                  /*  TODO: always interrupt?  */                  /*  TODO: always interrupt?  */
466                  d->delayed_interrupt = INT_DELAY;                  d->int_assert = 1;
467                  break;                  break;
468    
469          case WDCC_RECAL:          case WDCC_RECAL:
470                  debug("[ wdc: RECAL drive %i ]\n", d->drive);                  debug("[ wdc: RECAL drive %i ]\n", d->drive);
471                  d->delayed_interrupt = INT_DELAY;                  d->int_assert = 1;
472                  break;                  break;
473    
474          case WDCC_IDENTIFY:          case WDCC_IDENTIFY:
# Line 506  void wdc_command(struct cpu *cpu, struct Line 481  void wdc_command(struct cpu *cpu, struct
481                          wdc_addtoinbuf(d, d->identify_struct[i+1]);                          wdc_addtoinbuf(d, d->identify_struct[i+1]);
482                          wdc_addtoinbuf(d, d->identify_struct[i+0]);                          wdc_addtoinbuf(d, d->identify_struct[i+0]);
483                  }                  }
484                  d->delayed_interrupt = INT_DELAY;                  d->int_assert = 1;
485                  break;                  break;
486    
487          case WDCC_IDLE_IMMED:          case WDCC_IDLE_IMMED:
488                  debug("[ wdc: IDLE_IMMED drive %i ]\n", d->drive);                  debug("[ wdc: IDLE_IMMED drive %i ]\n", d->drive);
489                  /*  TODO: interrupt here?  */                  /*  TODO: interrupt here?  */
490                  d->delayed_interrupt = INT_DELAY;                  d->int_assert = 1;
491                  break;                  break;
492    
493          case WDCC_SETMULTI:          case WDCC_SETMULTI:
494                  debug("[ wdc: SETMULTI drive %i ]\n", d->drive);                  debug("[ wdc: SETMULTI drive %i ]\n", d->drive);
495                  /*  TODO: interrupt here?  */                  /*  TODO: interrupt here?  */
496                  d->delayed_interrupt = INT_DELAY;                  d->int_assert = 1;
497                  break;                  break;
498    
499          case ATAPI_SOFT_RESET:          case ATAPI_SOFT_RESET:
500                  debug("[ wdc: ATAPI_SOFT_RESET drive %i ]\n", d->drive);                  debug("[ wdc: ATAPI_SOFT_RESET drive %i ]\n", d->drive);
501                  /*  TODO: interrupt here?  */                  /*  TODO: interrupt here?  */
502                  d->delayed_interrupt = INT_DELAY;                  d->int_assert = 1;
503                  break;                  break;
504    
505          case ATAPI_PKT_CMD:          case ATAPI_PKT_CMD:
506                  debug("[ wdc: ATAPI_PKT_CMD drive %i ]\n", d->drive);                  debug("[ wdc: ATAPI_PKT_CMD drive %i ]\n", d->drive);
507                  /*  TODO: interrupt here?  */                  /*  TODO: interrupt here?  */
508                  /*  d->delayed_interrupt = INT_DELAY;  */                  /*  d->int_assert = 1;  */
509                  d->atapi_cmd_in_progress = 1;                  d->atapi_cmd_in_progress = 1;
510                  d->atapi_phase = PHASE_CMDOUT;                  d->atapi_phase = PHASE_CMDOUT;
511                  break;                  break;
# Line 538  void wdc_command(struct cpu *cpu, struct Line 513  void wdc_command(struct cpu *cpu, struct
513          case WDCC_DIAGNOSE:          case WDCC_DIAGNOSE:
514                  debug("[ wdc: WDCC_DIAGNOSE drive %i: TODO ]\n", d->drive);                  debug("[ wdc: WDCC_DIAGNOSE drive %i: TODO ]\n", d->drive);
515                  /*  TODO: interrupt here?  */                  /*  TODO: interrupt here?  */
516                  d->delayed_interrupt = INT_DELAY;                  d->int_assert = 1;
517                  d->error = 1;           /*  No error?  */                  d->error = 1;           /*  No error?  */
518                  break;                  break;
519    
# Line 562  void wdc_command(struct cpu *cpu, struct Line 537  void wdc_command(struct cpu *cpu, struct
537  }  }
538    
539    
 /*  
  *  dev_wdc_access():  
  */  
540  DEVICE_ACCESS(wdc)  DEVICE_ACCESS(wdc)
541  {  {
542          struct wdc_data *d = extra;          struct wdc_data *d = extra;
# Line 635  DEVICE_ACCESS(wdc) Line 607  DEVICE_ACCESS(wdc)
607                                          } else                                          } else
608                                                  d->atapi_phase =                                                  d->atapi_phase =
609                                                      PHASE_COMPLETED;                                                      PHASE_COMPLETED;
610                                          d->delayed_interrupt = INT_DELAY;                                          d->int_assert = 1;
611                                  }                                  }
612                          } else {                          } else {
613  #if 0  #if 0
# Line 645  DEVICE_ACCESS(wdc) Line 617  DEVICE_ACCESS(wdc)
617                                      ((d->inbuf_tail - d->inbuf_head) % 512)                                      ((d->inbuf_tail - d->inbuf_head) % 512)
618                                      == 0)                                      == 0)
619  #endif  #endif
620                                          d->delayed_interrupt = INT_DELAY;                                          d->int_assert = 1;
621                          }                          }
622                  } else {                  } else {
623                          int inbuf_len;                          int inbuf_len;
# Line 760  DEVICE_ACCESS(wdc) Line 732  DEVICE_ACCESS(wdc)
732                                          exit(1);                                          exit(1);
733                                  }                                  }
734    
735                                  d->delayed_interrupt = INT_DELAY;                                  d->int_assert = 1;
736                          }                          }
737    
738                          if (( d->write_in_progress == WDCC_WRITEMULTI &&                          if (( d->write_in_progress == WDCC_WRITEMULTI &&
# Line 794  DEVICE_ACCESS(wdc) Line 766  DEVICE_ACCESS(wdc)
766                                  d->write_count -= count;                                  d->write_count -= count;
767                                  d->write_offset += 512 * count;                                  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;
# Line 903  DEVICE_ACCESS(wdc) Line 875  DEVICE_ACCESS(wdc)
875                          if (!quiet_mode)                          if (!quiet_mode)
876                                  debug("[ wdc: read from STATUS: 0x%02x ]\n",                                  debug("[ wdc: read from STATUS: 0x%02x ]\n",
877                                      (int)odata);                                      (int)odata);
878                          cpu_interrupt_ack(cpu, d->irq_nr);                          INTERRUPT_DEASSERT(d->irq);
879                          d->int_asserted = 0;                          d->int_assert = 0;
                         d->delayed_interrupt = 0;  
880                  } else {                  } else {
881                          debug("[ wdc: write to COMMAND: 0x%02x ]\n",(int)idata);                          debug("[ wdc: write to COMMAND: 0x%02x ]\n",(int)idata);
882                          wdc_command(cpu, d, idata);                          wdc_command(cpu, d, idata);
# Line 921  DEVICE_ACCESS(wdc) Line 892  DEVICE_ACCESS(wdc)
892                              (int)relative_addr, (int)idata);                              (int)relative_addr, (int)idata);
893          }          }
894    
895            /*  Assert interrupt, if necessary:  */
896          if (cpu->machine->machine_type != MACHINE_HPCMIPS &&          dev_wdc_tick(cpu, extra);
             cpu->machine->machine_type != MACHINE_EVBMIPS &&  
             cpu->machine->machine_type != MACHINE_ALGOR &&  
             cpu->machine->machine_type != MACHINE_BEBOX)  
                 dev_wdc_tick(cpu, extra);  
897    
898  ret:  ret:
899          if (writeflag == MEM_READ) {          if (writeflag == MEM_READ) {
# Line 952  DEVINIT(wdc) Line 919  DEVINIT(wdc)
919                  exit(1);                  exit(1);
920          }          }
921          memset(d, 0, sizeof(struct wdc_data));          memset(d, 0, sizeof(struct wdc_data));
922          d->irq_nr     = devinit->irq_nr;  
923            INTERRUPT_CONNECT(devinit->interrupt_path, d->irq);
924          d->addr_mult  = devinit->addr_mult;          d->addr_mult  = devinit->addr_mult;
925          d->data_debug = 1;          d->data_debug = 1;
926          d->io_enabled = 1;          d->io_enabled = 1;
# Line 995  DEVINIT(wdc) Line 963  DEVINIT(wdc)
963              devinit->addr, DEV_WDC_LENGTH * devinit->addr_mult, dev_wdc_access,              devinit->addr, DEV_WDC_LENGTH * devinit->addr_mult, dev_wdc_access,
964              d, DM_DEFAULT, NULL);              d, DM_DEFAULT, NULL);
965    
         if (devinit->machine->machine_type != MACHINE_HPCMIPS &&  
             devinit->machine->machine_type != MACHINE_EVBMIPS)  
                 tick_shift += 1;  
   
966          machine_add_tickfunction(devinit->machine, dev_wdc_tick,          machine_add_tickfunction(devinit->machine, dev_wdc_tick,
967              d, tick_shift, 0.0);              d, tick_shift, 0.0);
968    

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

  ViewVC Help
Powered by ViewVC 1.1.26