/[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 31 by dpavlin, Mon Oct 8 16:19:56 2007 UTC revision 32 by dpavlin, Mon Oct 8 16:20:58 2007 UTC
# Line 25  Line 25 
25   *  SUCH DAMAGE.   *  SUCH DAMAGE.
26   *     *  
27   *   *
28   *  $Id: dev_mc146818.c,v 1.86 2006/06/22 13:22:41 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 other machines is also similar to the MC146818.)   *  (DS1687 as used in some other machines is also similar to the MC146818.)
# 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    
# Line 63  Line 64 
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;
         int     timebase_hz;  
         int     interrupt_hz;  
         int     irq_nr;  
   
         int     previous_second;  
         int     n_seconds_elapsed;  
         int     uip_threshold;  
   
         int     interrupt_every_x_cycles;  
         int     cycles_left_until_interrupt;  
   
         int     ugly_netbsd_prep_hack_done;  
         int     ugly_netbsd_prep_hack_sec;  
89  };  };
90    
91    
# Line 101  struct mc_data { Line 102  struct mc_data {
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          recalc_interrupt_cycle(cpu, d);          if ((d->reg[MC_REGB * 4] & MC_REGB_PIE) && pti > 0) {
122                    static int warned = 0;
123                    if (pti > 800 && !warned) {
124                            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 -= (1 << TICK_SHIFT);                      lagging behind the real clock:  */
132                    {
133                  if (d->cycles_left_until_interrupt < 0 ||                          static int x = 0;
134                      d->cycles_left_until_interrupt >=                          if (++x == 1) {
135                      d->interrupt_every_x_cycles) {                                  x = 0;
136                          /*  fatal("[ rtc interrupt (every %i cycles) ]\n",                                  printf("%i ", pti);
137                              d->interrupt_every_x_cycles);  */                                  fflush(stdout);
138                          cpu_interrupt(cpu, d->irq_nr);                          }
139                    }
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 241  static void mc146818_update_time(struct Line 213  static void mc146818_update_time(struct
213           */           */
214          switch (d->access_style) {          switch (d->access_style) {
215          case MC146818_ALGOR:          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;                  d->reg[4 * MC_YEAR] += 80;
223                  break;                  break;
224          case MC146818_ARC_NEC:          case MC146818_ARC_NEC:
# Line 474  int dev_mc146818_access(struct cpu *cpu, Line 452  int dev_mc146818_access(struct cpu *cpu,
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 587  int dev_mc146818_access(struct cpu *cpu, Line 567  int dev_mc146818_access(struct cpu *cpu,
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          }          }

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

  ViewVC Help
Powered by ViewVC 1.1.26