/[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 32 by dpavlin, Mon Oct 8 16:20:58 2007 UTC
# Line 1  Line 1 
1  /*  /*
2   *  Copyright (C) 2003-2005  Anders Gavare.  All rights reserved.   *  Copyright (C) 2003-2006  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_mc146818.c,v 1.68 2005/02/07 05:51:54 debug Exp $   *  $Id: dev_mc146818.c,v 1.91 2006/10/07 03:20:19 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 48  Line 48 
48  #include "machine.h"  #include "machine.h"
49  #include "memory.h"  #include "memory.h"
50  #include "misc.h"  #include "misc.h"
51    #include "timer.h"
52    
53  #include "mc146818reg.h"  #include "mc146818reg.h"
54    
55    
56  #define to_bcd(x)       ( ((x)/10) * 16 + ((x)%10) )  #define to_bcd(x)       ( ((x)/10) * 16 + ((x)%10) )
57    #define from_bcd(x)     ( ((x)>>4) * 10 + ((x)&15) )
58    
59  /*  #define MC146818_DEBUG  */  /*  #define MC146818_DEBUG  */
60    
61  #define TICK_STEPS_SHIFT        14  #define TICK_SHIFT      14
62    
63    
64  /*  256 on DECstation, SGI uses reg at 72*4 as the Century  */  /*  256 on DECstation, SGI uses reg at 72*4 as the Century  */
65  #define N_REGISTERS     1024  #define N_REGISTERS     1024
66  struct mc_data {  struct mc_data {
67          int     access_style;          int             access_style;
68          int     last_addr;          int             last_addr;
69    
70          int     register_choice;          int             register_choice;
71          int     reg[N_REGISTERS];          int             reg[N_REGISTERS];
72          int     addrdiv;          int             addrdiv;
73    
74            int             use_bcd;
75    
76            int             timebase_hz;
77            int             interrupt_hz;
78            int             old_interrupt_hz;
79            int             irq_nr;
80            struct timer    *timer;
81            volatile int    pending_timer_interrupts;
82    
83            int             previous_second;
84            int             n_seconds_elapsed;
85            int             uip_threshold;
86    
87          int     use_bcd;          int             ugly_netbsd_prep_hack_done;
88            int             ugly_netbsd_prep_hack_sec;
89          int     timebase_hz;  };
         int     interrupt_hz;  
         int     irq_nr;  
90    
         int     previous_second;  
91    
92          int     interrupt_every_x_cycles;  /*
93          int     cycles_left_until_interrupt;   *  Ugly hack to fool NetBSD/prep to accept the clock.  (See mcclock_isa_match
94  };   *  in NetBSD's arch/prep/isa/mcclock_isa.c for details.)
95     */
96    #define NETBSD_HACK_INIT                0
97    #define NETBSD_HACK_FIRST_1             1
98    #define NETBSD_HACK_FIRST_2             2
99    #define NETBSD_HACK_SECOND_1            3
100    #define NETBSD_HACK_SECOND_2            4
101    #define NETBSD_HACK_DONE                5
102    
103    
104  /*  /*
105   *  recalc_interrupt_cycle():   *  timer_tick():
106   *   *
107   *  If automatic_clock_adjustment is turned on, then emulated_hz is modified   *  Called d->interrupt_hz times per (real-world) second.
  *  dynamically.  We have to recalculate how often interrupts are to be  
  *  triggered.  
108   */   */
109  static void recalc_interrupt_cycle(struct cpu *cpu, struct mc_data *d)  static void timer_tick(struct timer *timer, void *extra)
110  {  {
111          int64_t emulated_hz = cpu->machine->emulated_hz;          struct mc_data *d = (struct mc_data *) extra;
112  #if 0          d->pending_timer_interrupts ++;
         static int warning_printed = 0;  
   
         /*  
          *  A hack to make Ultrix run, even on very fast host machines.  
          *  
          *  (Ultrix was probably never meant to be run on machines with  
          *  faster CPUs than around 33 MHz or so.)  
          */  
         if (d->access_style == MC146818_DEC && emulated_hz > 30000000) {  
                 if (!warning_printed) {  
                         fatal("\n*********************************************"  
                             "**********************************\n\n   Your hos"  
                             "t machine is too fast! The emulated CPU speed wil"  
                             "l be limited to\n   30 MHz, and clocks inside the"  
                             " emulated environment might go faster than\n   in"  
                             " the real world.  You have been warned.\n\n******"  
                             "*************************************************"  
                             "************************\n\n");  
                         warning_printed = 1;  
                 }  
   
                 emulated_hz = 30000000;  
         }  
 #endif  
   
         if (d->interrupt_hz > 0)  
                 d->interrupt_every_x_cycles =  
                     emulated_hz / d->interrupt_hz;  
         else  
                 d->interrupt_every_x_cycles = 0;  
113  }  }
114    
115    
116  /*  DEVICE_TICK(mc146818)
  *  dev_mc146818_tick():  
  */  
 void dev_mc146818_tick(struct cpu *cpu, void *extra)  
117  {  {
118          struct mc_data *d = extra;          struct mc_data *d = extra;
119            int pti = d->pending_timer_interrupts;
120    
121          if (d == NULL)          if ((d->reg[MC_REGB * 4] & MC_REGB_PIE) && pti > 0) {
122                  return;                  static int warned = 0;
123                    if (pti > 800 && !warned) {
124          recalc_interrupt_cycle(cpu, d);                          warned = 1;
125                            fatal("[ WARNING: MC146818 interrupts lost, "
126                                "host too slow? ]\n");
127                    }
128    
129          if ((d->reg[MC_REGB * 4] & MC_REGB_PIE) &&  #if 0
130               d->interrupt_every_x_cycles > 0) {                  /*  For debugging, to see how much the interrupts are
131                  d->cycles_left_until_interrupt -=                      lagging behind the real clock:  */
132                      (1 << TICK_STEPS_SHIFT);                  {
133                            static int x = 0;
134                  if (d->cycles_left_until_interrupt < 0 ||                          if (++x == 1) {
135                      d->cycles_left_until_interrupt >=                                  x = 0;
136                      d->interrupt_every_x_cycles) {                                  printf("%i ", pti);
137                          /*  debug("[ rtc interrupt (every %i cycles) ]\n",                                  fflush(stdout);
138                              d->interrupt_every_x_cycles);  */                          }
139                          cpu_interrupt(cpu, d->irq_nr);                  }
140    #endif
141    
142                          d->reg[MC_REGC * 4] |= MC_REGC_PF;                  cpu_interrupt(cpu, d->irq_nr);
143    
144                          /*  Reset the cycle countdown:  */                  d->reg[MC_REGC * 4] |= MC_REGC_PF;
                         while (d->cycles_left_until_interrupt < 0)  
                                 d->cycles_left_until_interrupt +=  
                                     d->interrupt_every_x_cycles;  
                 }  
145          }          }
146    
147          if (d->reg[MC_REGC * 4] & MC_REGC_UF ||          if (d->reg[MC_REGC * 4] & MC_REGC_UF ||
# Line 223  static void mc146818_update_time(struct Line 208  static void mc146818_update_time(struct
208          d->reg[4 * MC_MONTH] = tmp->tm_mon + 1;          d->reg[4 * MC_MONTH] = tmp->tm_mon + 1;
209          d->reg[4 * MC_YEAR]  = tmp->tm_year;          d->reg[4 * MC_YEAR]  = tmp->tm_year;
210    
211            /*
212             *  Special hacks for emulating the behaviour of various machines:
213             */
214          switch (d->access_style) {          switch (d->access_style) {
215            case MC146818_ALGOR:
216                    /*
217                     *  NetBSD/evbmips sources indicate that the Algor year base
218                     *  is 1920. This makes the time work with NetBSD in Malta
219                     *  emulation. However, for Linux, commenting out this line
220                     *  works better.  (TODO: Find a way to make both work?)
221                     */
222                    d->reg[4 * MC_YEAR] += 80;
223                    break;
224          case MC146818_ARC_NEC:          case MC146818_ARC_NEC:
225                  d->reg[4 * MC_YEAR] += (0x18 - 104);                  d->reg[4 * MC_YEAR] += (0x18 - 104);
226                  break;                  break;
227            case MC146818_CATS:
228                    d->reg[4 * MC_YEAR] %= 100;
229                    break;
230          case MC146818_SGI:          case MC146818_SGI:
231                  /*                  /*
232                   *  NetBSD/sgimips assumes data in BCD format.                   *  NetBSD/sgimips assumes data in BCD format.
# Line 248  static void mc146818_update_time(struct Line 248  static void mc146818_update_time(struct
248                            (d->reg[4 * MC_YEAR] - 30 + 40)                            (d->reg[4 * MC_YEAR] - 30 + 40)
249                          : (d->reg[4 * MC_YEAR] - 40)                          : (d->reg[4 * MC_YEAR] - 40)
250                        );                        );
   
251                  /*  Century:  */                  /*  Century:  */
252                  d->reg[72 * 4] = 19 + (tmp->tm_year / 100);                  d->reg[72 * 4] = 19 + (tmp->tm_year / 100);
   
253                  break;                  break;
254          case MC146818_DEC:          case MC146818_DEC:
255                  /*                  /*
# Line 298  int dev_mc146818_access(struct cpu *cpu, Line 296  int dev_mc146818_access(struct cpu *cpu,
296          struct tm *tmp;          struct tm *tmp;
297          time_t timet;          time_t timet;
298          struct mc_data *d = extra;          struct mc_data *d = extra;
299          int i, relative_addr = r;          int relative_addr = r;
300            size_t i;
301    
302          relative_addr /= d->addrdiv;          relative_addr /= d->addrdiv;
303    
304          /*  Different ways of accessing the registers:  */          /*  Different ways of accessing the registers:  */
305          switch (d->access_style) {          switch (d->access_style) {
306            case MC146818_ALGOR:
307            case MC146818_CATS:
308          case MC146818_PC_CMOS:          case MC146818_PC_CMOS:
309                  if (relative_addr == 0x70 || relative_addr == 0x00) {                  if ((relative_addr & 1) == 0x00) {
310                          if (writeflag == MEM_WRITE) {                          if (writeflag == MEM_WRITE) {
311                                  d->last_addr = data[0];                                  d->last_addr = data[0];
312                                  return 1;                                  return 1;
# Line 313  int dev_mc146818_access(struct cpu *cpu, Line 314  int dev_mc146818_access(struct cpu *cpu,
314                                  data[0] = d->last_addr;                                  data[0] = d->last_addr;
315                                  return 1;                                  return 1;
316                          }                          }
317                  } else if (relative_addr == 0x71 || relative_addr == 0x01)                  } else
318                          relative_addr = d->last_addr * 4;                          relative_addr = d->last_addr * 4;
                 else {  
                         fatal("[ mc146818: not accessed as an "  
                             "MC146818_PC_CMOS device! ]\n");  
                 }  
319                  break;                  break;
320          case MC146818_ARC_NEC:          case MC146818_ARC_NEC:
321                  if (relative_addr == 0x01) {                  if (relative_addr == 0x01) {
# Line 351  int dev_mc146818_access(struct cpu *cpu, Line 348  int dev_mc146818_access(struct cpu *cpu,
348                   *  should be ignored. It works _almost_ as DEC, if offsets are                   *  should be ignored. It works _almost_ as DEC, if offsets are
349                   *  divided by 0x40.                   *  divided by 0x40.
350                   */                   */
351                    break;
352            case MC146818_PMPPC:
353                    relative_addr *= 4;
354                    break;
355          default:          default:
356                  ;                  ;
357          }          }
# Line 360  int dev_mc146818_access(struct cpu *cpu, Line 361  int dev_mc146818_access(struct cpu *cpu,
361                  fatal("[ mc146818: write to addr=0x%04x (len %i): ",                  fatal("[ mc146818: write to addr=0x%04x (len %i): ",
362                      (int)relative_addr, (int)len);                      (int)relative_addr, (int)len);
363                  for (i=0; i<len; i++)                  for (i=0; i<len; i++)
364                          fatal("%02x ", data[i]);                          fatal("0x%02x ", data[i]);
365                  fatal("]\n");                  fatal("]\n");
366          }          }
367  #endif  #endif
368    
369          /*          /*
370           *  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  
371           *  it hangs forever during bootup.  (These do not cause interrupts,           *  it hangs forever during bootup.  (These do not cause interrupts,
372           *  but it is good enough... Sprite polls this, iirc.)           *  but it is good enough... Sprite polls this, iirc.)
373             *
374             *  Linux on at least sgimips and evbmips (Malta) wants the UIP bit
375             *  in REGA to be updated once a second.
376           */           */
377          timet = time(NULL);          if (relative_addr == MC_REGA*4 || relative_addr == MC_REGC*4) {
378          tmp = gmtime(&timet);                  timet = time(NULL);
379          d->reg[MC_REGC * 4] &= ~MC_REGC_UF;                  tmp = gmtime(&timet);
380          if (tmp->tm_sec != d->previous_second) {                  d->reg[MC_REGC * 4] &= ~MC_REGC_UF;
381                  d->reg[MC_REGC * 4] |= MC_REGC_UF;                  if (tmp->tm_sec != d->previous_second) {
382                  d->reg[MC_REGC * 4] |= MC_REGC_IRQF;                          d->n_seconds_elapsed ++;
383                  d->previous_second = tmp->tm_sec;                          d->previous_second = tmp->tm_sec;
384                    }
385                    if (d->n_seconds_elapsed > d->uip_threshold) {
386                            d->n_seconds_elapsed = 0;
387    
388                  /*  For some reason, some Linux/DECstation KN04 kernels want                          d->reg[MC_REGA * 4] |= MC_REGA_UIP;
389                      the PF (periodic flag) bit set, even though interrupts  
390                      are not enabled?  */                          d->reg[MC_REGC * 4] |= MC_REGC_UF;
391                  d->reg[MC_REGC * 4] |= MC_REGC_PF;                          d->reg[MC_REGC * 4] |= MC_REGC_IRQF;
392    
393                            /*  For some reason, some Linux/DECstation KN04
394                                kernels want the PF (periodic flag) bit set,
395                                even though interrupts are not enabled?  */
396                            d->reg[MC_REGC * 4] |= MC_REGC_PF;
397                    } else
398                            d->reg[MC_REGA * 4] &= ~MC_REGA_UIP;
399          }          }
400    
401          /*  RTC data is in either BCD format or binary:  */          /*  RTC data is in either BCD format or binary:  */
402          if (d->use_bcd) {          if (d->use_bcd)
403                  d->reg[MC_REGB * 4] &= ~(1 << 2);                  d->reg[MC_REGB * 4] &= ~(1 << 2);
404          } else {          else
405                  d->reg[MC_REGB * 4] |= (1 << 2);                  d->reg[MC_REGB * 4] |= (1 << 2);
         }  
406    
407          /*  RTC date/time is always Valid:  */          /*  RTC date/time is always Valid:  */
408          d->reg[MC_REGD * 4] |= MC_REGD_VRT;          d->reg[MC_REGD * 4] |= MC_REGD_VRT;
# Line 444  int dev_mc146818_access(struct cpu *cpu, Line 446  int dev_mc146818_access(struct cpu *cpu,
446                          case MC_RATE_8_Hz:      d->interrupt_hz = 8;    break;                          case MC_RATE_8_Hz:      d->interrupt_hz = 8;    break;
447                          case MC_RATE_4_Hz:      d->interrupt_hz = 4;    break;                          case MC_RATE_4_Hz:      d->interrupt_hz = 4;    break;
448                          case MC_RATE_2_Hz:      d->interrupt_hz = 2;    break;                          case MC_RATE_2_Hz:      d->interrupt_hz = 2;    break;
449                          default:                          default:/*  debug("[ mc146818: unimplemented "
                                 /*  debug("[ mc146818: unimplemented "  
450                                      "MC_REGA RS: %i ]\n",                                      "MC_REGA RS: %i ]\n",
451                                      data[0] & MC_REGA_RSMASK);  */                                      data[0] & MC_REGA_RSMASK);  */
452                                  ;                                  ;
453                          }                          }
454    
455                          recalc_interrupt_cycle(cpu, d);                          if (d->interrupt_hz != d->old_interrupt_hz) {
456                                    debug("[ rtc changed to interrupt at %i Hz ]\n",
457                          d->cycles_left_until_interrupt =                                      d->interrupt_hz);
458                                  d->interrupt_every_x_cycles;  
459                                    d->old_interrupt_hz = d->interrupt_hz;
460    
461                                    if (d->timer == NULL)
462                                            d->timer = timer_add(d->interrupt_hz,
463                                                timer_tick, d);
464                                    else
465                                            timer_update_frequency(d->timer,
466                                                d->interrupt_hz);
467                            }
468    
469                          d->reg[MC_REGA * 4] =                          d->reg[MC_REGA * 4] =
470                              data[0] & (MC_REGA_RSMASK | MC_REGA_DVMASK);                              data[0] & (MC_REGA_RSMASK | MC_REGA_DVMASK);
   
                         debug("[ rtc set to interrupt every %i:th cycle ]\n",  
                             d->interrupt_every_x_cycles);  
471                          break;                          break;
472                  case MC_REGB*4:                  case MC_REGB*4:
                         if (((data[0] ^ d->reg[MC_REGB*4]) & MC_REGB_PIE))  
                                 d->cycles_left_until_interrupt =  
                                     d->interrupt_every_x_cycles;  
473                          d->reg[MC_REGB*4] = data[0];                          d->reg[MC_REGB*4] = data[0];
474                          if (!(data[0] & MC_REGB_PIE)) {                          if (!(data[0] & MC_REGB_PIE)) {
475                                  cpu_interrupt_ack(cpu, d->irq_nr);                                  cpu_interrupt_ack(cpu, d->irq_nr);
                                 /*  d->cycles_left_until_interrupt =  
                                     d->interrupt_every_x_cycles;  */  
476                          }                          }
477    
478                          /*  debug("[ mc146818: write to MC_REGB, data[0] "                          /*  debug("[ mc146818: write to MC_REGB, data[0] "
479                              "= 0x%02x ]\n", data[0]);  */                              "= 0x%02x ]\n", data[0]);  */
480                          break;                          break;
# Line 483  int dev_mc146818_access(struct cpu *cpu, Line 486  int dev_mc146818_access(struct cpu *cpu,
486                  case 0x128:                  case 0x128:
487                          d->reg[relative_addr] = data[0];                          d->reg[relative_addr] = data[0];
488                          if (data[0] & 8) {                          if (data[0] & 8) {
489                                    int j;
490    
491                                  /*  Used on SGI to power off the machine.  */                                  /*  Used on SGI to power off the machine.  */
492                                  fatal("[ md146818: power off ]\n");                                  fatal("[ md146818: power off ]\n");
493                                  for (i=0; i<cpu->machine->ncpus; i++)                                  for (j=0; j<cpu->machine->ncpus; j++)
494                                          cpu->machine->cpus[i]->running = 0;                                          cpu->machine->cpus[j]->running = 0;
495                                  cpu->machine->                                  cpu->machine->
496                                      exit_without_entering_debugger = 1;                                      exit_without_entering_debugger = 1;
497                          }                          }
# Line 511  int dev_mc146818_access(struct cpu *cpu, Line 516  int dev_mc146818_access(struct cpu *cpu,
516                  case 0x15:                  case 0x15:
517                          break;                          break;
518                  case 4 * MC_SEC:                  case 4 * MC_SEC:
519                            if (d->ugly_netbsd_prep_hack_done < NETBSD_HACK_DONE) {
520                                    d->ugly_netbsd_prep_hack_done ++;
521                                    switch (d->ugly_netbsd_prep_hack_done) {
522                                    case NETBSD_HACK_FIRST_1:
523                                            d->ugly_netbsd_prep_hack_sec =
524                                                from_bcd(d->reg[relative_addr]);
525                                            break;
526                                    case NETBSD_HACK_FIRST_2:
527                                            d->reg[relative_addr] = to_bcd(
528                                                d->ugly_netbsd_prep_hack_sec);
529                                            break;
530                                    case NETBSD_HACK_SECOND_1:
531                                    case NETBSD_HACK_SECOND_2:
532                                            d->reg[relative_addr] = to_bcd((1 +
533                                                d->ugly_netbsd_prep_hack_sec) % 60);
534                                            break;
535                                    }
536                            }
537                  case 4 * MC_MIN:                  case 4 * MC_MIN:
538                  case 4 * MC_HOUR:                  case 4 * MC_HOUR:
539                  case 4 * MC_DOW:                  case 4 * MC_DOW:
# Line 527  int dev_mc146818_access(struct cpu *cpu, Line 550  int dev_mc146818_access(struct cpu *cpu,
550                          if (d->reg[MC_REGB * 4] & MC_REGB_SET)                          if (d->reg[MC_REGB * 4] & MC_REGB_SET)
551                                  break;                                  break;
552    
553                          mc146818_update_time(d);                          if (d->ugly_netbsd_prep_hack_done >= NETBSD_HACK_DONE)
554                                    mc146818_update_time(d);
555                            break;
556                    case 4 * MC_REGA:
557                          break;                          break;
558                  case 4 * MC_REGC:       /*  Interrupt ack.  */                  case 4 * MC_REGC:       /*  Interrupt ack.  */
559                          /*  NOTE: Acking is done below, _after_ the                          /*  NOTE: Acking is done below, _after_ the
560                              register has been read.  */                              register has been read.  */
561                          break;                          break;
562                  default:                  default:debug("[ mc146818: read from relative_addr = "
                         debug("[ mc146818: read from relative_addr = "  
563                              "%04x ]\n", (int)relative_addr);                              "%04x ]\n", (int)relative_addr);
                         ;  
564                  }                  }
565    
566                  data[0] = d->reg[relative_addr];                  data[0] = d->reg[relative_addr];
567    
568                  if (relative_addr == MC_REGC*4) {                  if (relative_addr == MC_REGC*4) {
569                          cpu_interrupt_ack(cpu, d->irq_nr);                          cpu_interrupt_ack(cpu, d->irq_nr);
570                          /*  d->cycles_left_until_interrupt =  
571                              d->interrupt_every_x_cycles;  */                          /*
572                             *  Acknowledging an interrupt decreases the
573                             *  number of pending "real world" timer ticks.
574                             */
575                            if (d->reg[MC_REGC * 4] & MC_REGC_PF)
576                                    d->pending_timer_interrupts --;
577    
578                          d->reg[MC_REGC * 4] = 0x00;                          d->reg[MC_REGC * 4] = 0x00;
579                  }                  }
580          }          }
# Line 554  int dev_mc146818_access(struct cpu *cpu, Line 584  int dev_mc146818_access(struct cpu *cpu,
584                  fatal("[ mc146818: read from addr=0x%04x (len %i): ",                  fatal("[ mc146818: read from addr=0x%04x (len %i): ",
585                      (int)relative_addr, (int)len);                      (int)relative_addr, (int)len);
586                  for (i=0; i<len; i++)                  for (i=0; i<len; i++)
587                          fatal("%02x ", data[i]);                          fatal("0x%02x ", data[i]);
588                  fatal("]\n");                  fatal("]\n");
589          }          }
590  #endif  #endif
# Line 587  void dev_mc146818_init(struct machine *m Line 617  void dev_mc146818_init(struct machine *m
617          d->access_style  = access_style;          d->access_style  = access_style;
618          d->addrdiv       = addrdiv;          d->addrdiv       = addrdiv;
619    
620            d->use_bcd = 0;
621            switch (access_style) {
622            case MC146818_SGI:
623            case MC146818_PC_CMOS:
624            case MC146818_PMPPC:
625                    d->use_bcd = 1;
626            }
627    
628            if (machine->machine_type != MACHINE_PREP) {
629                    /*  NetBSD/prep has a really ugly clock detection code;
630                        no other machines/OSes don't need this.  */
631                    d->ugly_netbsd_prep_hack_done = NETBSD_HACK_DONE;
632            }
633    
634            if (access_style == MC146818_DEC) {
635          /*  Station Ethernet Address, on DECstation 3100:  */          /*  Station Ethernet Address, on DECstation 3100:  */
636          for (i=0; i<6; i++)          for (i=0; i<6; i++)
637                  ether_address[i] = 0x10 * (i+1);                  ether_address[i] = 0x10 * (i+1);
638    
639          d->reg[0x01] = ether_address[0];                  d->reg[0x01] = ether_address[0];
640          d->reg[0x05] = ether_address[1];                  d->reg[0x05] = ether_address[1];
641          d->reg[0x09] = ether_address[2];                  d->reg[0x09] = ether_address[2];
642          d->reg[0x0d] = ether_address[3];                  d->reg[0x0d] = ether_address[3];
643          d->reg[0x11] = ether_address[4];                  d->reg[0x11] = ether_address[4];
644          d->reg[0x15] = ether_address[5];                  d->reg[0x15] = ether_address[5];
645          /*  TODO:  19, 1d, 21, 25 = checksum bytes 1,2,2,1 resp. */                  /*  TODO:  19, 1d, 21, 25 = checksum bytes 1,2,2,1 resp. */
646          d->reg[0x29] = ether_address[5];                  d->reg[0x29] = ether_address[5];
647          d->reg[0x2d] = ether_address[4];                  d->reg[0x2d] = ether_address[4];
648          d->reg[0x31] = ether_address[3];                  d->reg[0x31] = ether_address[3];
649          d->reg[0x35] = ether_address[2];                  d->reg[0x35] = ether_address[2];
650          d->reg[0x39] = ether_address[1];                  d->reg[0x39] = ether_address[1];
651          d->reg[0x3d] = ether_address[1];                  d->reg[0x3d] = ether_address[1];
652          d->reg[0x41] = ether_address[0];                  d->reg[0x41] = ether_address[0];
653          d->reg[0x45] = ether_address[1];                  d->reg[0x45] = ether_address[1];
654          d->reg[0x49] = ether_address[2];                  d->reg[0x49] = ether_address[2];
655          d->reg[0x4d] = ether_address[3];                  d->reg[0x4d] = ether_address[3];
656          d->reg[0x51] = ether_address[4];                  d->reg[0x51] = ether_address[4];
657          d->reg[0x55] = ether_address[5];                  d->reg[0x55] = ether_address[5];
658          /*  TODO:  59, 5d = checksum bytes 1,2 resp. */                  /*  TODO:  59, 5d = checksum bytes 1,2 resp. */
659          d->reg[0x61] = 0xff;                  d->reg[0x61] = 0xff;
660          d->reg[0x65] = 0x00;                  d->reg[0x65] = 0x00;
661          d->reg[0x69] = 0x55;                  d->reg[0x69] = 0x55;
662          d->reg[0x6d] = 0xaa;                  d->reg[0x6d] = 0xaa;
663          d->reg[0x71] = 0xff;                  d->reg[0x71] = 0xff;
664          d->reg[0x75] = 0x00;                  d->reg[0x75] = 0x00;
665          d->reg[0x79] = 0x55;                  d->reg[0x79] = 0x55;
666          d->reg[0x7d] = 0xaa;                  d->reg[0x7d] = 0xaa;
   
         /*  Only SGI uses BCD format (?)  */  
         d->use_bcd = 0;  
         if (access_style == MC146818_SGI)  
                 d->use_bcd = 1;  
667    
         if (access_style == MC146818_DEC) {  
668                  /*  Battery valid, for DECstations  */                  /*  Battery valid, for DECstations  */
669                  d->reg[0xf8] = 1;                  d->reg[0xf8] = 1;
670          }          }
671    
672            /*
673             *  uip_threshold should ideally be 1, but when Linux polls the UIP bit
674             *  it looses speed. This hack gives Linux the impression that the cpu
675             *  is uip_threshold times faster than the slow clock it would
676             *  otherwise detect.
677             *
678             *  TODO:  Find out if this messes up Sprite emulation; if so, then
679             *         this hack has to be removed.
680             */
681            d->uip_threshold = 8;
682    
683          if (access_style == MC146818_ARC_JAZZ)          if (access_style == MC146818_ARC_JAZZ)
684                  memory_device_register(mem, "mc146818_jazz", 0x90000070ULL,                  memory_device_register(mem, "mc146818_jazz", 0x90000070ULL,
685                      1, dev_mc146818_jazz_access, d, MEM_DEFAULT, NULL);                      1, dev_mc146818_jazz_access, d, DM_DEFAULT, NULL);
686    
687          dev_len = DEV_MC146818_LENGTH;          dev_len = DEV_MC146818_LENGTH;
688          switch (access_style) {          switch (access_style) {
689            case MC146818_CATS:
690          case MC146818_PC_CMOS:          case MC146818_PC_CMOS:
691                  dev_len = 2;                  dev_len = 2;
692                  break;                  break;
# Line 645  void dev_mc146818_init(struct machine *m Line 696  void dev_mc146818_init(struct machine *m
696    
697          memory_device_register(mem, "mc146818", baseaddr,          memory_device_register(mem, "mc146818", baseaddr,
698              dev_len * addrdiv, dev_mc146818_access,              dev_len * addrdiv, dev_mc146818_access,
699              d, MEM_DEFAULT, NULL);              d, DM_DEFAULT, NULL);
700    
701          mc146818_update_time(d);          mc146818_update_time(d);
702    
703          machine_add_tickfunction(machine, dev_mc146818_tick,          machine_add_tickfunction(machine, dev_mc146818_tick, d,
704              d, TICK_STEPS_SHIFT);              TICK_SHIFT, 0.0);
705  }  }
706    

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

  ViewVC Help
Powered by ViewVC 1.1.26