/[gxemul]/trunk/src/devices/dev_mc146818.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_mc146818.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 16 by dpavlin, Mon Oct 8 16:19:01 2007 UTC
# Line 25  Line 25 
25   *  SUCH DAMAGE.   *  SUCH DAMAGE.
26   *     *  
27   *   *
28   *  $Id: dev_mc146818.c,v 1.68 2005/02/07 05:51:54 debug Exp $   *  $Id: dev_mc146818.c,v 1.75 2005/10/09 22:21:31 debug Exp $
29   *     *  
30   *  MC146818 real-time clock, used by many different machines types.   *  MC146818 real-time clock, used by many different machines types.
31   *  (DS1687 as used in some SGI machines is similar to MC146818.)   *  (DS1687 as used in some other machines is also similar to the MC146818.)
32   *   *
33   *  This device contains Date/time, the machine's ethernet address (on   *  This device contains Date/time, the machine's ethernet address (on
34   *  DECstation 3100), and can cause periodic (hardware) interrupts.   *  DECstation 3100), and can cause periodic (hardware) interrupts.
# Line 56  Line 56 
56    
57  /*  #define MC146818_DEBUG  */  /*  #define MC146818_DEBUG  */
58    
59  #define TICK_STEPS_SHIFT        14  #define TICK_SHIFT      14
60    
61    
62  /*  256 on DECstation, SGI uses reg at 72*4 as the Century  */  /*  256 on DECstation, SGI uses reg at 72*4 as the Century  */
# Line 140  void dev_mc146818_tick(struct cpu *cpu, Line 140  void dev_mc146818_tick(struct cpu *cpu,
140    
141          if ((d->reg[MC_REGB * 4] & MC_REGB_PIE) &&          if ((d->reg[MC_REGB * 4] & MC_REGB_PIE) &&
142               d->interrupt_every_x_cycles > 0) {               d->interrupt_every_x_cycles > 0) {
143                  d->cycles_left_until_interrupt -=                  d->cycles_left_until_interrupt -= (1 << TICK_SHIFT);
                     (1 << TICK_STEPS_SHIFT);  
144    
145                  if (d->cycles_left_until_interrupt < 0 ||                  if (d->cycles_left_until_interrupt < 0 ||
146                      d->cycles_left_until_interrupt >=                      d->cycles_left_until_interrupt >=
# Line 223  static void mc146818_update_time(struct Line 222  static void mc146818_update_time(struct
222          d->reg[4 * MC_MONTH] = tmp->tm_mon + 1;          d->reg[4 * MC_MONTH] = tmp->tm_mon + 1;
223          d->reg[4 * MC_YEAR]  = tmp->tm_year;          d->reg[4 * MC_YEAR]  = tmp->tm_year;
224    
225            /*
226             *  Special hacks for emulating the behaviour of various machines:
227             */
228          switch (d->access_style) {          switch (d->access_style) {
229          case MC146818_ARC_NEC:          case MC146818_ARC_NEC:
230                  d->reg[4 * MC_YEAR] += (0x18 - 104);                  d->reg[4 * MC_YEAR] += (0x18 - 104);
231                  break;                  break;
232            case MC146818_CATS:
233                    d->reg[4 * MC_YEAR] %= 100;
234                    break;
235          case MC146818_SGI:          case MC146818_SGI:
236                  /*                  /*
237                   *  NetBSD/sgimips assumes data in BCD format.                   *  NetBSD/sgimips assumes data in BCD format.
# Line 248  static void mc146818_update_time(struct Line 253  static void mc146818_update_time(struct
253                            (d->reg[4 * MC_YEAR] - 30 + 40)                            (d->reg[4 * MC_YEAR] - 30 + 40)
254                          : (d->reg[4 * MC_YEAR] - 40)                          : (d->reg[4 * MC_YEAR] - 40)
255                        );                        );
   
256                  /*  Century:  */                  /*  Century:  */
257                  d->reg[72 * 4] = 19 + (tmp->tm_year / 100);                  d->reg[72 * 4] = 19 + (tmp->tm_year / 100);
   
258                  break;                  break;
259          case MC146818_DEC:          case MC146818_DEC:
260                  /*                  /*
# Line 304  int dev_mc146818_access(struct cpu *cpu, Line 307  int dev_mc146818_access(struct cpu *cpu,
307    
308          /*  Different ways of accessing the registers:  */          /*  Different ways of accessing the registers:  */
309          switch (d->access_style) {          switch (d->access_style) {
310            case MC146818_CATS:
311          case MC146818_PC_CMOS:          case MC146818_PC_CMOS:
312                  if (relative_addr == 0x70 || relative_addr == 0x00) {                  if ((relative_addr & 1) == 0x00) {
313                          if (writeflag == MEM_WRITE) {                          if (writeflag == MEM_WRITE) {
314                                  d->last_addr = data[0];                                  d->last_addr = data[0];
315                                  return 1;                                  return 1;
# Line 313  int dev_mc146818_access(struct cpu *cpu, Line 317  int dev_mc146818_access(struct cpu *cpu,
317                                  data[0] = d->last_addr;                                  data[0] = d->last_addr;
318                                  return 1;                                  return 1;
319                          }                          }
320                  } else if (relative_addr == 0x71 || relative_addr == 0x01)                  } else
321                          relative_addr = d->last_addr * 4;                          relative_addr = d->last_addr * 4;
                 else {  
                         fatal("[ mc146818: not accessed as an "  
                             "MC146818_PC_CMOS device! ]\n");  
                 }  
322                  break;                  break;
323          case MC146818_ARC_NEC:          case MC146818_ARC_NEC:
324                  if (relative_addr == 0x01) {                  if (relative_addr == 0x01) {
# Line 366  int dev_mc146818_access(struct cpu *cpu, Line 366  int dev_mc146818_access(struct cpu *cpu,
366  #endif  #endif
367    
368          /*          /*
369           *  For some reason, Linux/sgimips relies on the UIP bit to go           *  Sprite seems to wants UF interrupt status, once every second, or
          *  on and off. Without this code, booting Linux takes forever:  
          */  
         d->reg[MC_REGA * 4] &= ~MC_REGA_UIP;  
 #if 1  
         /*  TODO:  solve this more nicely  */  
         if ((random() & 0xff) == 0)  
                 d->reg[MC_REGA * 4] ^= MC_REGA_UIP;  
 #endif  
   
         /*  
          *  Sprite seens to wants UF interrupt status, once every second, or  
370           *  it hangs forever during bootup.  (These do not cause interrupts,           *  it hangs forever during bootup.  (These do not cause interrupts,
371           *  but it is good enough... Sprite polls this, iirc.)           *  but it is good enough... Sprite polls this, iirc.)
372             *
373             *  Linux on at least sgimips and evbmips (Malta) wants the UIP bit
374             *  in REGA to be updated once a second.
375           */           */
376          timet = time(NULL);          timet = time(NULL);
377          tmp = gmtime(&timet);          tmp = gmtime(&timet);
378          d->reg[MC_REGC * 4] &= ~MC_REGC_UF;          d->reg[MC_REGC * 4] &= ~MC_REGC_UF;
379    
380          if (tmp->tm_sec != d->previous_second) {          if (tmp->tm_sec != d->previous_second) {
381                    d->reg[MC_REGA * 4] &= ~MC_REGA_UIP;
382    
383                  d->reg[MC_REGC * 4] |= MC_REGC_UF;                  d->reg[MC_REGC * 4] |= MC_REGC_UF;
384                  d->reg[MC_REGC * 4] |= MC_REGC_IRQF;                  d->reg[MC_REGC * 4] |= MC_REGC_IRQF;
385                  d->previous_second = tmp->tm_sec;                  d->previous_second = tmp->tm_sec;
# Line 393  int dev_mc146818_access(struct cpu *cpu, Line 388  int dev_mc146818_access(struct cpu *cpu,
388                      the PF (periodic flag) bit set, even though interrupts                      the PF (periodic flag) bit set, even though interrupts
389                      are not enabled?  */                      are not enabled?  */
390                  d->reg[MC_REGC * 4] |= MC_REGC_PF;                  d->reg[MC_REGC * 4] |= MC_REGC_PF;
391          }          } else
392                    d->reg[MC_REGA * 4] |= MC_REGA_UIP;
393    
394          /*  RTC data is in either BCD format or binary:  */          /*  RTC data is in either BCD format or binary:  */
395          if (d->use_bcd) {          if (d->use_bcd)
396                  d->reg[MC_REGB * 4] &= ~(1 << 2);                  d->reg[MC_REGB * 4] &= ~(1 << 2);
397          } else {          else
398                  d->reg[MC_REGB * 4] |= (1 << 2);                  d->reg[MC_REGB * 4] |= (1 << 2);
         }  
399    
400          /*  RTC date/time is always Valid:  */          /*  RTC date/time is always Valid:  */
401          d->reg[MC_REGD * 4] |= MC_REGD_VRT;          d->reg[MC_REGD * 4] |= MC_REGD_VRT;
# Line 587  void dev_mc146818_init(struct machine *m Line 582  void dev_mc146818_init(struct machine *m
582          d->access_style  = access_style;          d->access_style  = access_style;
583          d->addrdiv       = addrdiv;          d->addrdiv       = addrdiv;
584    
585            /*  Only SGIs and PCs use BCD format (?)  */
586            d->use_bcd = 0;
587            if (access_style == MC146818_SGI || access_style == MC146818_PC_CMOS)
588                    d->use_bcd = 1;
589    
590            if (access_style == MC146818_DEC) {
591          /*  Station Ethernet Address, on DECstation 3100:  */          /*  Station Ethernet Address, on DECstation 3100:  */
592          for (i=0; i<6; i++)          for (i=0; i<6; i++)
593                  ether_address[i] = 0x10 * (i+1);                  ether_address[i] = 0x10 * (i+1);
594    
595          d->reg[0x01] = ether_address[0];                  d->reg[0x01] = ether_address[0];
596          d->reg[0x05] = ether_address[1];                  d->reg[0x05] = ether_address[1];
597          d->reg[0x09] = ether_address[2];                  d->reg[0x09] = ether_address[2];
598          d->reg[0x0d] = ether_address[3];                  d->reg[0x0d] = ether_address[3];
599          d->reg[0x11] = ether_address[4];                  d->reg[0x11] = ether_address[4];
600          d->reg[0x15] = ether_address[5];                  d->reg[0x15] = ether_address[5];
601          /*  TODO:  19, 1d, 21, 25 = checksum bytes 1,2,2,1 resp. */                  /*  TODO:  19, 1d, 21, 25 = checksum bytes 1,2,2,1 resp. */
602          d->reg[0x29] = ether_address[5];                  d->reg[0x29] = ether_address[5];
603          d->reg[0x2d] = ether_address[4];                  d->reg[0x2d] = ether_address[4];
604          d->reg[0x31] = ether_address[3];                  d->reg[0x31] = ether_address[3];
605          d->reg[0x35] = ether_address[2];                  d->reg[0x35] = ether_address[2];
606          d->reg[0x39] = ether_address[1];                  d->reg[0x39] = ether_address[1];
607          d->reg[0x3d] = ether_address[1];                  d->reg[0x3d] = ether_address[1];
608          d->reg[0x41] = ether_address[0];                  d->reg[0x41] = ether_address[0];
609          d->reg[0x45] = ether_address[1];                  d->reg[0x45] = ether_address[1];
610          d->reg[0x49] = ether_address[2];                  d->reg[0x49] = ether_address[2];
611          d->reg[0x4d] = ether_address[3];                  d->reg[0x4d] = ether_address[3];
612          d->reg[0x51] = ether_address[4];                  d->reg[0x51] = ether_address[4];
613          d->reg[0x55] = ether_address[5];                  d->reg[0x55] = ether_address[5];
614          /*  TODO:  59, 5d = checksum bytes 1,2 resp. */                  /*  TODO:  59, 5d = checksum bytes 1,2 resp. */
615          d->reg[0x61] = 0xff;                  d->reg[0x61] = 0xff;
616          d->reg[0x65] = 0x00;                  d->reg[0x65] = 0x00;
617          d->reg[0x69] = 0x55;                  d->reg[0x69] = 0x55;
618          d->reg[0x6d] = 0xaa;                  d->reg[0x6d] = 0xaa;
619          d->reg[0x71] = 0xff;                  d->reg[0x71] = 0xff;
620          d->reg[0x75] = 0x00;                  d->reg[0x75] = 0x00;
621          d->reg[0x79] = 0x55;                  d->reg[0x79] = 0x55;
622          d->reg[0x7d] = 0xaa;                  d->reg[0x7d] = 0xaa;
623    
         /*  Only SGI uses BCD format (?)  */  
         d->use_bcd = 0;  
         if (access_style == MC146818_SGI)  
                 d->use_bcd = 1;  
   
         if (access_style == MC146818_DEC) {  
624                  /*  Battery valid, for DECstations  */                  /*  Battery valid, for DECstations  */
625                  d->reg[0xf8] = 1;                  d->reg[0xf8] = 1;
626          }          }
# Line 636  void dev_mc146818_init(struct machine *m Line 631  void dev_mc146818_init(struct machine *m
631    
632          dev_len = DEV_MC146818_LENGTH;          dev_len = DEV_MC146818_LENGTH;
633          switch (access_style) {          switch (access_style) {
634            case MC146818_CATS:
635          case MC146818_PC_CMOS:          case MC146818_PC_CMOS:
636                  dev_len = 2;                  dev_len = 2;
637                  break;                  break;
# Line 649  void dev_mc146818_init(struct machine *m Line 645  void dev_mc146818_init(struct machine *m
645    
646          mc146818_update_time(d);          mc146818_update_time(d);
647    
648          machine_add_tickfunction(machine, dev_mc146818_tick,          machine_add_tickfunction(machine, dev_mc146818_tick, d, TICK_SHIFT);
             d, TICK_STEPS_SHIFT);  
649  }  }
650    

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

  ViewVC Help
Powered by ViewVC 1.1.26