/[gxemul]/trunk/src/devices/dev_footbridge.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_footbridge.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 31 by dpavlin, Mon Oct 8 16:20:40 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_footbridge.c,v 1.44 2006/08/11 17:43:30 debug Exp $   *  $Id: dev_footbridge.c,v 1.48 2006/09/30 10:09:19 debug Exp $
29   *   *
30   *  Footbridge. Used in Netwinder and Cats.   *  Footbridge. Used in Netwinder and Cats.
31   *   *
# Line 49  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    
55  #include "dc21285reg.h"  #include "dc21285reg.h"
56    
57  #define DEV_FOOTBRIDGE_TICK_SHIFT       14  #define DEV_FOOTBRIDGE_TICK_SHIFT       14
58  #define DEV_FOOTBRIDGE_LENGTH           0x400  #define DEV_FOOTBRIDGE_LENGTH           0x400
59  #define TIMER_POLL_THRESHOLD            15  
60    
61    static void timer_tick0(struct timer *t, void *extra)
62    { ((struct footbridge_data *)extra)->pending_timer_interrupts[0] ++; }
63    static void timer_tick1(struct timer *t, void *extra)
64    { ((struct footbridge_data *)extra)->pending_timer_interrupts[1] ++; }
65    static void timer_tick2(struct timer *t, void *extra)
66    { ((struct footbridge_data *)extra)->pending_timer_interrupts[2] ++; }
67    static void timer_tick3(struct timer *t, void *extra)
68    { ((struct footbridge_data *)extra)->pending_timer_interrupts[3] ++; }
69    
70    
71    static void reload_timer_value(struct cpu *cpu, struct footbridge_data *d,
72            int timer_nr)
73    {
74            double freq = (double)cpu->machine->emulated_hz;
75            int cycles = d->timer_load[timer_nr];
76    
77            if (d->timer_control[timer_nr] & TIMER_FCLK_16)
78                    cycles <<= 4;
79            else if (d->timer_control[timer_nr] & TIMER_FCLK_256)
80                    cycles <<= 8;
81            freq /= (double)cycles;
82    
83            d->timer_value[timer_nr] = d->timer_load[timer_nr];
84            d->timer_tick_countdown[timer_nr] = 1;
85    
86            /*  printf("%i: %i -> %f Hz\n", timer_nr,
87                d->timer_load[timer_nr], freq);  */
88    
89            if (d->timer[timer_nr] == NULL) {
90                    switch (timer_nr) {
91                    case 0: d->timer[0] = timer_add(freq, timer_tick0, d); break;
92                    case 1: d->timer[1] = timer_add(freq, timer_tick1, d); break;
93                    case 2: d->timer[2] = timer_add(freq, timer_tick2, d); break;
94                    case 3: d->timer[3] = timer_add(freq, timer_tick3, d); break;
95                    }
96            } else {
97                    timer_update_frequency(d->timer[timer_nr], freq);
98            }
99    }
100    
101    
102  /*  /*
103   *  dev_footbridge_tick():   *  dev_footbridge_tick():
104   *   *
105   *  The 4 footbridge timers should decrease every now and then, and cause   *  The 4 footbridge timers should decrease and cause interrupts. Periodic
106   *  interrupts. Periodic interrupts restart as soon as they are acknowledged,   *  interrupts restart as soon as they are acknowledged, non-periodic
107   *  non-periodic interrupts need to be "reloaded" to restart.   *  interrupts need to be "reloaded" to restart.
108     *
109     *  TODO: Hm. I thought I had solved this, but it didn't quite work.
110     *        This needs to be re-checked against documentation, sometime.
111   */   */
112  void dev_footbridge_tick(struct cpu *cpu, void *extra)  void dev_footbridge_tick(struct cpu *cpu, void *extra)
113  {  {
114          int i;          int i;
115          struct footbridge_data *d = (struct footbridge_data *) extra;          struct footbridge_data *d = (struct footbridge_data *) extra;
116    
         if (!d->timer_being_read)  
                 d->timer_poll_mode = 0;  
   
117          for (i=0; i<N_FOOTBRIDGE_TIMERS; i++) {          for (i=0; i<N_FOOTBRIDGE_TIMERS; i++) {
118                  unsigned int amount = 1 << DEV_FOOTBRIDGE_TICK_SHIFT;                  if (d->timer_control[i] & TIMER_ENABLE) {
119                  if (d->timer_control[i] & TIMER_FCLK_16)                          if (d->pending_timer_interrupts[i] > 0) {
120                          amount >>= 4;                                  d->timer_value[i] = random() % d->timer_load[i];
                 else if (d->timer_control[i] & TIMER_FCLK_256)  
                         amount >>= 8;  
   
                 if (d->timer_tick_countdown[i] == 0)  
                         continue;  
   
                 if (d->timer_value[i] > amount)  
                         d->timer_value[i] -= amount;  
                 else  
                         d->timer_value[i] = 0;  
   
                 if (d->timer_value[i] == 0) {  
                         d->timer_tick_countdown[i] --;  
                         if (d->timer_tick_countdown[i] > 0)  
                                 continue;  
   
                         if (d->timer_control[i] & TIMER_ENABLE)  
121                                  cpu_interrupt(cpu, IRQ_TIMER_1 + i);                                  cpu_interrupt(cpu, IRQ_TIMER_1 + i);
122                          d->timer_tick_countdown[i] = 0;                          }
123                  }                  }
124          }          }
125  }  }
# Line 338  DEVICE_ACCESS(footbridge) Line 362  DEVICE_ACCESS(footbridge)
362                  if (writeflag == MEM_READ)                  if (writeflag == MEM_READ)
363                          odata = d->timer_load[timer_nr];                          odata = d->timer_load[timer_nr];
364                  else {                  else {
365                          d->timer_value[timer_nr] =                          d->timer_load[timer_nr] = idata & TIMER_MAX_VAL;
366                              d->timer_load[timer_nr] = idata & TIMER_MAX_VAL;                          reload_timer_value(cpu, d, timer_nr);
367                          debug("[ footbridge: timer %i (1-based), value %i ]\n",                          /*  debug("[ footbridge: timer %i (1-based), "
368                              timer_nr + 1, (int)d->timer_value[timer_nr]);                              "value %i ]\n", timer_nr + 1,
369                          d->timer_tick_countdown[timer_nr] = 1;                              (int)d->timer_value[timer_nr]);  */
370                          cpu_interrupt_ack(cpu, IRQ_TIMER_1 + timer_nr);                          cpu_interrupt_ack(cpu, IRQ_TIMER_1 + timer_nr);
371                  }                  }
372                  break;                  break;
373    
374          case TIMER_1_VALUE:          case TIMER_1_VALUE:
375                  if (writeflag == MEM_READ) {                  if (writeflag == MEM_READ)
                         /*  
                          *  NOTE/TODO: This is INCORRECT but speeds up NetBSD  
                          *  and OpenBSD boot sequences: if the timer is polled  
                          *  "very often" (such as during bootup), then this  
                          *  causes the timers to expire quickly.  
                          */  
                         d->timer_being_read = 1;  
                         d->timer_poll_mode ++;  
                         if (d->timer_poll_mode >= TIMER_POLL_THRESHOLD) {  
                                 d->timer_poll_mode = TIMER_POLL_THRESHOLD;  
                                 dev_footbridge_tick(cpu, d);  
                                 dev_footbridge_tick(cpu, d);  
                                 dev_footbridge_tick(cpu, d);  
                         }  
376                          odata = d->timer_value[timer_nr];                          odata = d->timer_value[timer_nr];
377                          d->timer_being_read = 0;                  else
                 } else  
378                          d->timer_value[timer_nr] = idata & TIMER_MAX_VAL;                          d->timer_value[timer_nr] = idata & TIMER_MAX_VAL;
379                  break;                  break;
380    
# Line 381  DEVICE_ACCESS(footbridge) Line 390  DEVICE_ACCESS(footbridge)
390                                  exit(1);                                  exit(1);
391                          }                          }
392                          if (idata & TIMER_ENABLE) {                          if (idata & TIMER_ENABLE) {
393                                  d->timer_value[timer_nr] =                                  reload_timer_value(cpu, d, timer_nr);
394                                      d->timer_load[timer_nr];                          } else {
395                                  d->timer_tick_countdown[timer_nr] = 1;                                  d->pending_timer_interrupts[timer_nr] = 0;
396                          }                          }
397                          cpu_interrupt_ack(cpu, IRQ_TIMER_1 + timer_nr);                          cpu_interrupt_ack(cpu, IRQ_TIMER_1 + timer_nr);
398                  }                  }
# Line 391  DEVICE_ACCESS(footbridge) Line 400  DEVICE_ACCESS(footbridge)
400    
401          case TIMER_1_CLEAR:          case TIMER_1_CLEAR:
402                  if (d->timer_control[timer_nr] & TIMER_MODE_PERIODIC) {                  if (d->timer_control[timer_nr] & TIMER_MODE_PERIODIC) {
403                          d->timer_value[timer_nr] = d->timer_load[timer_nr];                          reload_timer_value(cpu, d, timer_nr);
                         d->timer_tick_countdown[timer_nr] = 1;  
404                  }                  }
405    
406                    if (d->pending_timer_interrupts[timer_nr] > 0) {
407                            d->pending_timer_interrupts[timer_nr] --;
408                    }
409    
410                  cpu_interrupt_ack(cpu, IRQ_TIMER_1 + timer_nr);                  cpu_interrupt_ack(cpu, IRQ_TIMER_1 + timer_nr);
411                  break;                  break;
412    

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

  ViewVC Help
Powered by ViewVC 1.1.26