/[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 42 by dpavlin, Mon Oct 8 16:22:32 2007 UTC
# Line 1  Line 1 
1  /*  /*
2   *  Copyright (C) 2003-2005  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.68 2005/02/07 05:51:54 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   *  (DS1687 as used in some SGI machines is similar to MC146818.)   *
32     *  (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
35   *  DECstation 3100), and can cause periodic (hardware) interrupts.   *  DECstation 3100), and can cause periodic (hardware) interrupts.
# 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    
56    
57  #define to_bcd(x)       ( ((x)/10) * 16 + ((x)%10) )  #define to_bcd(x)       ( ((x)/10) * 16 + ((x)%10) )
58    #define from_bcd(x)     ( ((x)>>4) * 10 + ((x)&15) )
59    
60  /*  #define MC146818_DEBUG  */  /*  #define MC146818_DEBUG  */
61    
62  #define TICK_STEPS_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;  
70    
71          int     use_bcd;          int             register_choice;
72            int             reg[N_REGISTERS];
73            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     timebase_hz;          int             ugly_netbsd_prep_hack_done;
89          int     interrupt_hz;          int             ugly_netbsd_prep_hack_sec;
90          int     irq_nr;  };
91    
         int     previous_second;  
92    
93          int     interrupt_every_x_cycles;  /*
94          int     cycles_left_until_interrupt;   *  Ugly hack to fool NetBSD/prep to accept the clock.  (See mcclock_isa_match
95  };   *  in NetBSD's arch/prep/isa/mcclock_isa.c for details.)
96     */
97    #define NETBSD_HACK_INIT                0
98    #define NETBSD_HACK_FIRST_1             1
99    #define NETBSD_HACK_FIRST_2             2
100    #define NETBSD_HACK_SECOND_1            3
101    #define NETBSD_HACK_SECOND_2            4
102    #define NETBSD_HACK_DONE                5
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          if (d == NULL)          if ((d->reg[MC_REGB * 4] & MC_REGB_PIE) && pti > 0) {
123                  return;  #if 0
124                    /*  For debugging, to see how much the interrupts are
125          recalc_interrupt_cycle(cpu, d);                      lagging behind the real clock:  */
126                    {
127          if ((d->reg[MC_REGB * 4] & MC_REGB_PIE) &&                          static int x = 0;
128               d->interrupt_every_x_cycles > 0) {                          if (++x == 1) {
129                  d->cycles_left_until_interrupt -=                                  x = 0;
130                      (1 << TICK_STEPS_SHIFT);                                  printf("%i ", pti);
131                                    fflush(stdout);
132                  if (d->cycles_left_until_interrupt < 0 ||                          }
133                      d->cycles_left_until_interrupt >=                  }
134                      d->interrupt_every_x_cycles) {  #endif
                         /*  debug("[ rtc interrupt (every %i cycles) ]\n",  
                             d->interrupt_every_x_cycles);  */  
                         cpu_interrupt(cpu, d->irq_nr);  
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 172  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 223  static void mc146818_update_time(struct Line 200  static void mc146818_update_time(struct
200          d->reg[4 * MC_MONTH] = tmp->tm_mon + 1;          d->reg[4 * MC_MONTH] = tmp->tm_mon + 1;
201          d->reg[4 * MC_YEAR]  = tmp->tm_year;          d->reg[4 * MC_YEAR]  = tmp->tm_year;
202    
203            /*
204             *  Special hacks for emulating the behaviour of various machines:
205             */
206          switch (d->access_style) {          switch (d->access_style) {
207            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;
215                    break;
216          case MC146818_ARC_NEC:          case MC146818_ARC_NEC:
217                  d->reg[4 * MC_YEAR] += (0x18 - 104);                  d->reg[4 * MC_YEAR] += (0x18 - 104);
218                  break;                  break;
219            case MC146818_CATS:
220                    d->reg[4 * MC_YEAR] %= 100;
221                    break;
222          case MC146818_SGI:          case MC146818_SGI:
223                  /*                  /*
224                   *  NetBSD/sgimips assumes data in BCD format.                   *  NetBSD/sgimips assumes data in BCD format.
# Line 248  static void mc146818_update_time(struct Line 240  static void mc146818_update_time(struct
240                            (d->reg[4 * MC_YEAR] - 30 + 40)                            (d->reg[4 * MC_YEAR] - 30 + 40)
241                          : (d->reg[4 * MC_YEAR] - 40)                          : (d->reg[4 * MC_YEAR] - 40)
242                        );                        );
   
243                  /*  Century:  */                  /*  Century:  */
244                  d->reg[72 * 4] = 19 + (tmp->tm_year / 100);                  d->reg[72 * 4] = 19 + (tmp->tm_year / 100);
   
245                  break;                  break;
246          case MC146818_DEC:          case MC146818_DEC:
247                  /*                  /*
# Line 286  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;
284          struct mc_data *d = extra;          size_t i;
285          int i, relative_addr = r;  
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:  */
291          switch (d->access_style) {          switch (d->access_style) {
292            case MC146818_ALGOR:
293            case MC146818_CATS:
294          case MC146818_PC_CMOS:          case MC146818_PC_CMOS:
295                  if (relative_addr == 0x70 || relative_addr == 0x00) {                  if ((relative_addr & 1) == 0x00) {
296                          if (writeflag == MEM_WRITE) {                          if (writeflag == MEM_WRITE) {
297                                  d->last_addr = data[0];                                  d->last_addr = data[0];
298                                  return 1;                                  return 1;
# Line 313  int dev_mc146818_access(struct cpu *cpu, Line 300  int dev_mc146818_access(struct cpu *cpu,
300                                  data[0] = d->last_addr;                                  data[0] = d->last_addr;
301                                  return 1;                                  return 1;
302                          }                          }
303                  } else if (relative_addr == 0x71 || relative_addr == 0x01)                  } else
304                          relative_addr = d->last_addr * 4;                          relative_addr = d->last_addr * 4;
                 else {  
                         fatal("[ mc146818: not accessed as an "  
                             "MC146818_PC_CMOS device! ]\n");  
                 }  
305                  break;                  break;
306          case MC146818_ARC_NEC:          case MC146818_ARC_NEC:
307                  if (relative_addr == 0x01) {                  if (relative_addr == 0x01) {
# Line 351  int dev_mc146818_access(struct cpu *cpu, Line 334  int dev_mc146818_access(struct cpu *cpu,
334                   *  should be ignored. It works _almost_ as DEC, if offsets are                   *  should be ignored. It works _almost_ as DEC, if offsets are
335                   *  divided by 0x40.                   *  divided by 0x40.
336                   */                   */
337                    break;
338            case MC146818_PMPPC:
339                    relative_addr *= 4;
340                    break;
341          default:          default:
342                  ;                  ;
343          }          }
# Line 360  int dev_mc146818_access(struct cpu *cpu, Line 347  int dev_mc146818_access(struct cpu *cpu,
347                  fatal("[ mc146818: write to addr=0x%04x (len %i): ",                  fatal("[ mc146818: write to addr=0x%04x (len %i): ",
348                      (int)relative_addr, (int)len);                      (int)relative_addr, (int)len);
349                  for (i=0; i<len; i++)                  for (i=0; i<len; i++)
350                          fatal("%02x ", data[i]);                          fatal("0x%02x ", data[i]);
351                  fatal("]\n");                  fatal("]\n");
352          }          }
353  #endif  #endif
354    
355          /*          /*
356           *  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  
357           *  it hangs forever during bootup.  (These do not cause interrupts,           *  it hangs forever during bootup.  (These do not cause interrupts,
358           *  but it is good enough... Sprite polls this, iirc.)           *  but it is good enough... Sprite polls this, iirc.)
359             *
360             *  Linux on at least sgimips and evbmips (Malta) wants the UIP bit
361             *  in REGA to be updated once a second.
362           */           */
363          timet = time(NULL);          if (relative_addr == MC_REGA*4 || relative_addr == MC_REGC*4) {
364          tmp = gmtime(&timet);                  timet = time(NULL);
365          d->reg[MC_REGC * 4] &= ~MC_REGC_UF;                  tmp = gmtime(&timet);
366          if (tmp->tm_sec != d->previous_second) {                  d->reg[MC_REGC * 4] &= ~MC_REGC_UF;
367                  d->reg[MC_REGC * 4] |= MC_REGC_UF;                  if (tmp->tm_sec != d->previous_second) {
368                  d->reg[MC_REGC * 4] |= MC_REGC_IRQF;                          d->n_seconds_elapsed ++;
369                  d->previous_second = tmp->tm_sec;                          d->previous_second = tmp->tm_sec;
370                    }
371                    if (d->n_seconds_elapsed > d->uip_threshold) {
372                            d->n_seconds_elapsed = 0;
373    
374                  /*  For some reason, some Linux/DECstation KN04 kernels want                          d->reg[MC_REGA * 4] |= MC_REGA_UIP;
375                      the PF (periodic flag) bit set, even though interrupts  
376                      are not enabled?  */                          d->reg[MC_REGC * 4] |= MC_REGC_UF;
377                  d->reg[MC_REGC * 4] |= MC_REGC_PF;                          d->reg[MC_REGC * 4] |= MC_REGC_IRQF;
378    
379                            /*  For some reason, some Linux/DECstation KN04
380                                kernels want the PF (periodic flag) bit set,
381                                even though interrupts are not enabled?  */
382                            d->reg[MC_REGC * 4] |= MC_REGC_PF;
383                    } else
384                            d->reg[MC_REGA * 4] &= ~MC_REGA_UIP;
385          }          }
386    
387          /*  RTC data is in either BCD format or binary:  */          /*  RTC data is in either BCD format or binary:  */
388          if (d->use_bcd) {          if (d->use_bcd)
389                  d->reg[MC_REGB * 4] &= ~(1 << 2);                  d->reg[MC_REGB * 4] &= ~(1 << 2);
390          } else {          else
391                  d->reg[MC_REGB * 4] |= (1 << 2);                  d->reg[MC_REGB * 4] |= (1 << 2);
         }  
392    
393          /*  RTC date/time is always Valid:  */          /*  RTC date/time is always Valid:  */
394          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 432  int dev_mc146818_access(struct cpu *cpu,
432                          case MC_RATE_8_Hz:      d->interrupt_hz = 8;    break;                          case MC_RATE_8_Hz:      d->interrupt_hz = 8;    break;
433                          case MC_RATE_4_Hz:      d->interrupt_hz = 4;    break;                          case MC_RATE_4_Hz:      d->interrupt_hz = 4;    break;
434                          case MC_RATE_2_Hz:      d->interrupt_hz = 2;    break;                          case MC_RATE_2_Hz:      d->interrupt_hz = 2;    break;
435                          default:                          default:/*  debug("[ mc146818: unimplemented "
                                 /*  debug("[ mc146818: unimplemented "  
436                                      "MC_REGA RS: %i ]\n",                                      "MC_REGA RS: %i ]\n",
437                                      data[0] & MC_REGA_RSMASK);  */                                      data[0] & MC_REGA_RSMASK);  */
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 483  int dev_mc146818_access(struct cpu *cpu, Line 472  int dev_mc146818_access(struct cpu *cpu,
472                  case 0x128:                  case 0x128:
473                          d->reg[relative_addr] = data[0];                          d->reg[relative_addr] = data[0];
474                          if (data[0] & 8) {                          if (data[0] & 8) {
475                                    int j;
476    
477                                  /*  Used on SGI to power off the machine.  */                                  /*  Used on SGI to power off the machine.  */
478                                  fatal("[ md146818: power off ]\n");                                  fatal("[ md146818: power off ]\n");
479                                  for (i=0; i<cpu->machine->ncpus; i++)                                  for (j=0; j<cpu->machine->ncpus; j++)
480                                          cpu->machine->cpus[i]->running = 0;                                          cpu->machine->cpus[j]->running = 0;
481                                  cpu->machine->                                  cpu->machine->
482                                      exit_without_entering_debugger = 1;                                      exit_without_entering_debugger = 1;
483                          }                          }
# Line 511  int dev_mc146818_access(struct cpu *cpu, Line 502  int dev_mc146818_access(struct cpu *cpu,
502                  case 0x15:                  case 0x15:
503                          break;                          break;
504                  case 4 * MC_SEC:                  case 4 * MC_SEC:
505                            if (d->ugly_netbsd_prep_hack_done < NETBSD_HACK_DONE) {
506                                    d->ugly_netbsd_prep_hack_done ++;
507                                    switch (d->ugly_netbsd_prep_hack_done) {
508                                    case NETBSD_HACK_FIRST_1:
509                                            d->ugly_netbsd_prep_hack_sec =
510                                                from_bcd(d->reg[relative_addr]);
511                                            break;
512                                    case NETBSD_HACK_FIRST_2:
513                                            d->reg[relative_addr] = to_bcd(
514                                                d->ugly_netbsd_prep_hack_sec);
515                                            break;
516                                    case NETBSD_HACK_SECOND_1:
517                                    case NETBSD_HACK_SECOND_2:
518                                            d->reg[relative_addr] = to_bcd((1 +
519                                                d->ugly_netbsd_prep_hack_sec) % 60);
520                                            break;
521                                    }
522                            }
523                  case 4 * MC_MIN:                  case 4 * MC_MIN:
524                  case 4 * MC_HOUR:                  case 4 * MC_HOUR:
525                  case 4 * MC_DOW:                  case 4 * MC_DOW:
# Line 527  int dev_mc146818_access(struct cpu *cpu, Line 536  int dev_mc146818_access(struct cpu *cpu,
536                          if (d->reg[MC_REGB * 4] & MC_REGB_SET)                          if (d->reg[MC_REGB * 4] & MC_REGB_SET)
537                                  break;                                  break;
538    
539                          mc146818_update_time(d);                          if (d->ugly_netbsd_prep_hack_done >= NETBSD_HACK_DONE)
540                                    mc146818_update_time(d);
541                            break;
542                    case 4 * MC_REGA:
543                          break;                          break;
544                  case 4 * MC_REGC:       /*  Interrupt ack.  */                  case 4 * MC_REGC:       /*  Interrupt ack.  */
545                          /*  NOTE: Acking is done below, _after_ the                          /*  NOTE: Acking is done below, _after_ the
546                              register has been read.  */                              register has been read.  */
547                          break;                          break;
548                  default:                  default:debug("[ mc146818: read from relative_addr = "
                         debug("[ mc146818: read from relative_addr = "  
549                              "%04x ]\n", (int)relative_addr);                              "%04x ]\n", (int)relative_addr);
                         ;  
550                  }                  }
551    
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 554  int dev_mc146818_access(struct cpu *cpu, Line 571  int dev_mc146818_access(struct cpu *cpu,
571                  fatal("[ mc146818: read from addr=0x%04x (len %i): ",                  fatal("[ mc146818: read from addr=0x%04x (len %i): ",
572                      (int)relative_addr, (int)len);                      (int)relative_addr, (int)len);
573                  for (i=0; i<len; i++)                  for (i=0; i<len; i++)
574                          fatal("%02x ", data[i]);                          fatal("0x%02x ", data[i]);
575                  fatal("]\n");                  fatal("]\n");
576          }          }
577  #endif  #endif
# Line 570  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          /*  Station Ethernet Address, on DECstation 3100:  */          INTERRUPT_CONNECT(irq_path, d->irq);
         for (i=0; i<6; i++)  
                 ether_address[i] = 0x10 * (i+1);  
   
         d->reg[0x01] = ether_address[0];  
         d->reg[0x05] = ether_address[1];  
         d->reg[0x09] = ether_address[2];  
         d->reg[0x0d] = ether_address[3];  
         d->reg[0x11] = ether_address[4];  
         d->reg[0x15] = ether_address[5];  
         /*  TODO:  19, 1d, 21, 25 = checksum bytes 1,2,2,1 resp. */  
         d->reg[0x29] = ether_address[5];  
         d->reg[0x2d] = ether_address[4];  
         d->reg[0x31] = ether_address[3];  
         d->reg[0x35] = ether_address[2];  
         d->reg[0x39] = ether_address[1];  
         d->reg[0x3d] = ether_address[1];  
         d->reg[0x41] = ether_address[0];  
         d->reg[0x45] = ether_address[1];  
         d->reg[0x49] = ether_address[2];  
         d->reg[0x4d] = ether_address[3];  
         d->reg[0x51] = ether_address[4];  
         d->reg[0x55] = ether_address[5];  
         /*  TODO:  59, 5d = checksum bytes 1,2 resp. */  
         d->reg[0x61] = 0xff;  
         d->reg[0x65] = 0x00;  
         d->reg[0x69] = 0x55;  
         d->reg[0x6d] = 0xaa;  
         d->reg[0x71] = 0xff;  
         d->reg[0x75] = 0x00;  
         d->reg[0x79] = 0x55;  
         d->reg[0x7d] = 0xaa;  
603    
         /*  Only SGI uses BCD format (?)  */  
604          d->use_bcd = 0;          d->use_bcd = 0;
605          if (access_style == MC146818_SGI)          switch (access_style) {
606            case MC146818_SGI:
607            case MC146818_PC_CMOS:
608            case MC146818_PMPPC:
609                  d->use_bcd = 1;                  d->use_bcd = 1;
610            }
611    
612            if (machine->machine_type != MACHINE_PREP) {
613                    /*  NetBSD/prep has a really ugly clock detection code;
614                        no other machines/OSes don't need this.  */
615                    d->ugly_netbsd_prep_hack_done = NETBSD_HACK_DONE;
616            }
617    
618          if (access_style == MC146818_DEC) {          if (access_style == MC146818_DEC) {
619                    /*  Station Ethernet Address, on DECstation 3100:  */
620                    for (i=0; i<6; i++)
621                            ether_address[i] = 0x10 * (i+1);
622    
623                    d->reg[0x01] = ether_address[0];
624                    d->reg[0x05] = ether_address[1];
625                    d->reg[0x09] = ether_address[2];
626                    d->reg[0x0d] = ether_address[3];
627                    d->reg[0x11] = ether_address[4];
628                    d->reg[0x15] = ether_address[5];
629                    /*  TODO:  19, 1d, 21, 25 = checksum bytes 1,2,2,1 resp. */
630                    d->reg[0x29] = ether_address[5];
631                    d->reg[0x2d] = ether_address[4];
632                    d->reg[0x31] = ether_address[3];
633                    d->reg[0x35] = ether_address[2];
634                    d->reg[0x39] = ether_address[1];
635                    d->reg[0x3d] = ether_address[1];
636                    d->reg[0x41] = ether_address[0];
637                    d->reg[0x45] = ether_address[1];
638                    d->reg[0x49] = ether_address[2];
639                    d->reg[0x4d] = ether_address[3];
640                    d->reg[0x51] = ether_address[4];
641                    d->reg[0x55] = ether_address[5];
642                    /*  TODO:  59, 5d = checksum bytes 1,2 resp. */
643                    d->reg[0x61] = 0xff;
644                    d->reg[0x65] = 0x00;
645                    d->reg[0x69] = 0x55;
646                    d->reg[0x6d] = 0xaa;
647                    d->reg[0x71] = 0xff;
648                    d->reg[0x75] = 0x00;
649                    d->reg[0x79] = 0x55;
650                    d->reg[0x7d] = 0xaa;
651    
652                  /*  Battery valid, for DECstations  */                  /*  Battery valid, for DECstations  */
653                  d->reg[0xf8] = 1;                  d->reg[0xf8] = 1;
654          }          }
655    
656            /*
657             *  uip_threshold should ideally be 1, but when Linux polls the UIP bit
658             *  it looses speed. This hack gives Linux the impression that the cpu
659             *  is uip_threshold times faster than the slow clock it would
660             *  otherwise detect.
661             *
662             *  TODO:  Find out if this messes up Sprite emulation; if so, then
663             *         this hack has to be removed.
664             */
665            d->uip_threshold = 8;
666    
667          if (access_style == MC146818_ARC_JAZZ)          if (access_style == MC146818_ARC_JAZZ)
668                  memory_device_register(mem, "mc146818_jazz", 0x90000070ULL,                  memory_device_register(mem, "mc146818_jazz", 0x90000070ULL,
669                      1, dev_mc146818_jazz_access, d, MEM_DEFAULT, NULL);                      1, dev_mc146818_jazz_access, d, DM_DEFAULT, NULL);
670    
671          dev_len = DEV_MC146818_LENGTH;          dev_len = DEV_MC146818_LENGTH;
672          switch (access_style) {          switch (access_style) {
673            case MC146818_CATS:
674          case MC146818_PC_CMOS:          case MC146818_PC_CMOS:
675                  dev_len = 2;                  dev_len = 2;
676                  break;                  break;
# Line 645  void dev_mc146818_init(struct machine *m Line 680  void dev_mc146818_init(struct machine *m
680    
681          memory_device_register(mem, "mc146818", baseaddr,          memory_device_register(mem, "mc146818", baseaddr,
682              dev_len * addrdiv, dev_mc146818_access,              dev_len * addrdiv, dev_mc146818_access,
683              d, MEM_DEFAULT, NULL);              d, DM_DEFAULT, NULL);
684    
685          mc146818_update_time(d);          mc146818_update_time(d);
686    
687          machine_add_tickfunction(machine, dev_mc146818_tick,          machine_add_tickfunction(machine, dev_mc146818_tick, d,
688              d, TICK_STEPS_SHIFT);              MC146818_TICK_SHIFT);
689  }  }
690    

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

  ViewVC Help
Powered by ViewVC 1.1.26