/[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 22 by dpavlin, Mon Oct 8 16:19:37 2007 UTC revision 42 by dpavlin, Mon Oct 8 16:22:32 2007 UTC
# Line 1  Line 1 
1  /*  /*
2   *  Copyright (C) 2003-2006  Anders Gavare.  All rights reserved.   *  Copyright (C) 2003-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_mc146818.c,v 1.84 2006/01/17 05:55:53 debug Exp $   *  $Id: dev_mc146818.c,v 1.99 2007/06/15 19:57:33 debug Exp $
29   *     *  
30   *  MC146818 real-time clock, used by many different machines types.   *  COMMENT: MC146818 real-time clock
31     *
32   *  (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.)
33   *   *
34   *  This device contains Date/time, the machine's ethernet address (on   *  This device contains Date/time, the machine's ethernet address (on
# Line 48  Line 49 
49  #include "machine.h"  #include "machine.h"
50  #include "memory.h"  #include "memory.h"
51  #include "misc.h"  #include "misc.h"
52    #include "timer.h"
53    
54  #include "mc146818reg.h"  #include "mc146818reg.h"
55    
# Line 57  Line 59 
59    
60  /*  #define MC146818_DEBUG  */  /*  #define MC146818_DEBUG  */
61    
62  #define TICK_SHIFT      14  #define MC146818_TICK_SHIFT     14
63    
64    
65  /*  256 on DECstation, SGI uses reg at 72*4 as the Century  */  /*  256 on DECstation, SGI uses reg at 72*4 as the Century  */
66  #define N_REGISTERS     1024  #define N_REGISTERS     1024
67  struct mc_data {  struct mc_data {
68          int     access_style;          int             access_style;
69          int     last_addr;          int             last_addr;
   
         int     register_choice;  
         int     reg[N_REGISTERS];  
         int     addrdiv;  
   
         int     use_bcd;  
70    
71          int     timebase_hz;          int             register_choice;
72          int     interrupt_hz;          int             reg[N_REGISTERS];
73          int     irq_nr;          int             addrdiv;
74    
75            int             use_bcd;
76    
77            int             timebase_hz;
78            int             interrupt_hz;
79            int             old_interrupt_hz;
80            struct interrupt irq;
81            struct timer    *timer;
82            volatile int    pending_timer_interrupts;
83    
84            int             previous_second;
85            int             n_seconds_elapsed;
86            int             uip_threshold;
87    
88          int     previous_second;          int             ugly_netbsd_prep_hack_done;
89          int     n_seconds_elapsed;          int             ugly_netbsd_prep_hack_sec;
         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;  
90  };  };
91    
92    
# Line 101  struct mc_data { Line 103  struct mc_data {
103    
104    
105  /*  /*
106   *  recalc_interrupt_cycle():   *  timer_tick():
107   *   *
108   *  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.  
109   */   */
110  static void recalc_interrupt_cycle(struct cpu *cpu, struct mc_data *d)  static void timer_tick(struct timer *timer, void *extra)
111  {  {
112          int64_t emulated_hz = cpu->machine->emulated_hz;          struct mc_data *d = (struct mc_data *) extra;
113  #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;  
114  }  }
115    
116    
117  /*  DEVICE_TICK(mc146818)
  *  dev_mc146818_tick():  
  */  
 void dev_mc146818_tick(struct cpu *cpu, void *extra)  
118  {  {
119          struct mc_data *d = extra;          struct mc_data *d = extra;
120            int pti = d->pending_timer_interrupts;
121    
122          recalc_interrupt_cycle(cpu, d);          if ((d->reg[MC_REGB * 4] & MC_REGB_PIE) && pti > 0) {
123    #if 0
124          if ((d->reg[MC_REGB * 4] & MC_REGB_PIE) &&                  /*  For debugging, to see how much the interrupts are
125               d->interrupt_every_x_cycles > 0) {                      lagging behind the real clock:  */
126                  d->cycles_left_until_interrupt -= (1 << TICK_SHIFT);                  {
127                            static int x = 0;
128                  if (d->cycles_left_until_interrupt < 0 ||                          if (++x == 1) {
129                      d->cycles_left_until_interrupt >=                                  x = 0;
130                      d->interrupt_every_x_cycles) {                                  printf("%i ", pti);
131                          /*  debug("[ rtc interrupt (every %i cycles) ]\n",                                  fflush(stdout);
132                              d->interrupt_every_x_cycles);  */                          }
133                          cpu_interrupt(cpu, d->irq_nr);                  }
134    #endif
135    
136                          d->reg[MC_REGC * 4] |= MC_REGC_PF;                  INTERRUPT_ASSERT(d->irq);
137    
138                          /*  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;  
                 }  
139          }          }
140    
141          if (d->reg[MC_REGC * 4] & MC_REGC_UF ||          if (d->reg[MC_REGC * 4] & MC_REGC_UF ||
# Line 186  void dev_mc146818_tick(struct cpu *cpu, Line 151  void dev_mc146818_tick(struct cpu *cpu,
151   *  It seems like JAZZ machines accesses the mc146818 by writing one byte to   *  It seems like JAZZ machines accesses the mc146818 by writing one byte to
152   *  0x90000070 and then reading or writing another byte at 0x......0004000.   *  0x90000070 and then reading or writing another byte at 0x......0004000.
153   */   */
154  int dev_mc146818_jazz_access(struct cpu *cpu, struct memory *mem,  DEVICE_ACCESS(mc146818_jazz)
         uint64_t relative_addr, unsigned char *data, size_t len,  
         int writeflag, void *extra)  
155  {  {
156          struct mc_data *d = extra;          struct mc_data *d = extra;
157    
# Line 242  static void mc146818_update_time(struct Line 205  static void mc146818_update_time(struct
205           */           */
206          switch (d->access_style) {          switch (d->access_style) {
207          case MC146818_ALGOR:          case MC146818_ALGOR:
208                    /*
209                     *  NetBSD/evbmips sources indicate that the Algor year base
210                     *  is 1920. This makes the time work with NetBSD in Malta
211                     *  emulation. However, for Linux, commenting out this line
212                     *  works better.  (TODO: Find a way to make both work?)
213                     */
214                  d->reg[4 * MC_YEAR] += 80;                  d->reg[4 * MC_YEAR] += 80;
215                  break;                  break;
216          case MC146818_ARC_NEC:          case MC146818_ARC_NEC:
# Line 307  static void mc146818_update_time(struct Line 276  static void mc146818_update_time(struct
276  }  }
277    
278    
279  /*  DEVICE_ACCESS(mc146818)
  *  dev_mc146818_access():  
  *  
  *  TODO: This access function only handles 8-bit accesses!  
  */  
 int dev_mc146818_access(struct cpu *cpu, struct memory *mem,  
         uint64_t r, unsigned char *data, size_t len,  
         int writeflag, void *extra)  
280  {  {
281            struct mc_data *d = extra;
282          struct tm *tmp;          struct tm *tmp;
283          time_t timet;          time_t timet;
         struct mc_data *d = extra;  
         int relative_addr = r;  
284          size_t i;          size_t i;
285    
286            /*  NOTE/TODO: This access function only handles 8-bit accesses!  */
287    
288          relative_addr /= d->addrdiv;          relative_addr /= d->addrdiv;
289    
290          /*  Different ways of accessing the registers:  */          /*  Different ways of accessing the registers:  */
# Line 475  int dev_mc146818_access(struct cpu *cpu, Line 438  int dev_mc146818_access(struct cpu *cpu,
438                                  ;                                  ;
439                          }                          }
440    
441                          recalc_interrupt_cycle(cpu, d);                          if (d->interrupt_hz != d->old_interrupt_hz) {
442                                    debug("[ rtc changed to interrupt at %i Hz ]\n",
443                          d->cycles_left_until_interrupt =                                      d->interrupt_hz);
444                                  d->interrupt_every_x_cycles;  
445                                    d->old_interrupt_hz = d->interrupt_hz;
446    
447                                    if (d->timer == NULL)
448                                            d->timer = timer_add(d->interrupt_hz,
449                                                timer_tick, d);
450                                    else
451                                            timer_update_frequency(d->timer,
452                                                d->interrupt_hz);
453                            }
454    
455                          d->reg[MC_REGA * 4] =                          d->reg[MC_REGA * 4] =
456                              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);  
457                          break;                          break;
458                  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;  
459                          d->reg[MC_REGB*4] = data[0];                          d->reg[MC_REGB*4] = data[0];
460                          if (!(data[0] & MC_REGB_PIE)) {                          if (!(data[0] & MC_REGB_PIE)) {
461                                  cpu_interrupt_ack(cpu, d->irq_nr);                                  INTERRUPT_DEASSERT(d->irq);
                                 /*  d->cycles_left_until_interrupt =  
                                     d->interrupt_every_x_cycles;  */  
462                          }                          }
463    
464                          /*  debug("[ mc146818: write to MC_REGB, data[0] "                          /*  debug("[ mc146818: write to MC_REGB, data[0] "
465                              "= 0x%02x ]\n", data[0]);  */                              "= 0x%02x ]\n", data[0]);  */
466                          break;                          break;
# Line 587  int dev_mc146818_access(struct cpu *cpu, Line 552  int dev_mc146818_access(struct cpu *cpu,
552                  data[0] = d->reg[relative_addr];                  data[0] = d->reg[relative_addr];
553    
554                  if (relative_addr == MC_REGC*4) {                  if (relative_addr == MC_REGC*4) {
555                          cpu_interrupt_ack(cpu, d->irq_nr);                          INTERRUPT_DEASSERT(d->irq);
556                          /*  d->cycles_left_until_interrupt =  
557                              d->interrupt_every_x_cycles;  */                          /*
558                             *  Acknowledging an interrupt decreases the
559                             *  number of pending "real world" timer ticks.
560                             */
561                            if (d->reg[MC_REGC * 4] & MC_REGC_PF &&
562                                d->pending_timer_interrupts > 0)
563                                    d->pending_timer_interrupts --;
564    
565                          d->reg[MC_REGC * 4] = 0x00;                          d->reg[MC_REGC * 4] = 0x00;
566                  }                  }
567          }          }
# Line 615  int dev_mc146818_access(struct cpu *cpu, Line 587  int dev_mc146818_access(struct cpu *cpu,
587   *  so it contains both rtc related stuff and the station's Ethernet address.   *  so it contains both rtc related stuff and the station's Ethernet address.
588   */   */
589  void dev_mc146818_init(struct machine *machine, struct memory *mem,  void dev_mc146818_init(struct machine *machine, struct memory *mem,
590          uint64_t baseaddr, int irq_nr, int access_style, int addrdiv)          uint64_t baseaddr, char *irq_path, int access_style, int addrdiv)
591  {  {
592          unsigned char ether_address[6];          unsigned char ether_address[6];
593          int i, dev_len;          int i, dev_len;
594          struct mc_data *d;          struct mc_data *d;
595    
596          d = malloc(sizeof(struct mc_data));          CHECK_ALLOCATION(d = malloc(sizeof(struct mc_data)));
         if (d == NULL) {  
                 fprintf(stderr, "out of memory\n");  
                 exit(1);  
         }  
   
597          memset(d, 0, sizeof(struct mc_data));          memset(d, 0, sizeof(struct mc_data));
598          d->irq_nr        = irq_nr;  
599          d->access_style  = access_style;          d->access_style  = access_style;
600          d->addrdiv       = addrdiv;          d->addrdiv       = addrdiv;
601    
602            INTERRUPT_CONNECT(irq_path, d->irq);
603    
604          d->use_bcd = 0;          d->use_bcd = 0;
605          switch (access_style) {          switch (access_style) {
606          case MC146818_SGI:          case MC146818_SGI:
# Line 647  void dev_mc146818_init(struct machine *m Line 616  void dev_mc146818_init(struct machine *m
616          }          }
617    
618          if (access_style == MC146818_DEC) {          if (access_style == MC146818_DEC) {
619          /*  Station Ethernet Address, on DECstation 3100:  */                  /*  Station Ethernet Address, on DECstation 3100:  */
620          for (i=0; i<6; i++)                  for (i=0; i<6; i++)
621                  ether_address[i] = 0x10 * (i+1);                          ether_address[i] = 0x10 * (i+1);
622    
623                  d->reg[0x01] = ether_address[0];                  d->reg[0x01] = ether_address[0];
624                  d->reg[0x05] = ether_address[1];                  d->reg[0x05] = ether_address[1];
# Line 715  void dev_mc146818_init(struct machine *m Line 684  void dev_mc146818_init(struct machine *m
684    
685          mc146818_update_time(d);          mc146818_update_time(d);
686    
687          machine_add_tickfunction(machine, dev_mc146818_tick, d, TICK_SHIFT);          machine_add_tickfunction(machine, dev_mc146818_tick, d,
688                MC146818_TICK_SHIFT);
689  }  }
690    

Legend:
Removed from v.22  
changed lines
  Added in v.42

  ViewVC Help
Powered by ViewVC 1.1.26