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

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

revision 20 by dpavlin, Mon Oct 8 16:19:23 2007 UTC revision 32 by dpavlin, Mon Oct 8 16:20:58 2007 UTC
# Line 1  Line 1 
1  /*  /*
2   *  Copyright (C) 2005  Anders Gavare.  All rights reserved.   *  Copyright (C) 2005-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_8253.c,v 1.7 2005/11/13 00:14:08 debug Exp $   *  $Id: dev_8253.c,v 1.16 2006/08/22 15:13:03 debug Exp $
  *    
  *  8253/8254 Programmable Interval Timer.  
29   *   *
30   *  This is mostly bogus.   *  Intel 8253/8254 Programmable Interval Timer
31     *
32     *  TODO/NOTE:
33     *      The timers don't really count down. Timer 0 causes clock interrupts
34     *      at a specific frequency, but reading the counter register would not
35     *      result in anything meaningful.
36     *
37     *  (Split counter[] into reset value and current value.)
38   */   */
39    
40  #include <stdio.h>  #include <stdio.h>
# Line 38  Line 43 
43    
44  #include "cpu.h"  #include "cpu.h"
45  #include "device.h"  #include "device.h"
 #include "devices.h"  
46  #include "emul.h"  #include "emul.h"
47  #include "machine.h"  #include "machine.h"
48  #include "memory.h"  #include "memory.h"
49  #include "misc.h"  #include "misc.h"
50    #include "timer.h"
51    
52    #include "i8253reg.h"
53    
54    
55    #define debug fatal
56    
57  #define DEV_8253_LENGTH         4  #define DEV_8253_LENGTH         4
58  #define TICK_SHIFT              14  #define TICK_SHIFT              14
59    
60    
61  struct pit8253_data {  struct pit8253_data {
         int             irq_nr;  
62          int             in_use;          int             in_use;
63    
64          int             counter_select;          int             counter_select;
65            uint8_t         mode_byte;
66    
67            int             mode[3];
68            int             counter[3];
69    
70            int             hz[3];
71    
72            struct timer    *timer0;
73            int             irq0_nr;
74            int             pending_interrupts_timer0;
75  };  };
76    
77    
78  /*  static void timer0_tick(struct timer *t, void *extra)
79   *  dev_8253_tick():  {
80   */              struct pit8253_data *d = (struct pit8253_data *) extra;
81  void dev_8253_tick(struct cpu *cpu, void *extra)          d->pending_interrupts_timer0 ++;
82    
83    #if 0
84            printf("%i ", d->pending_interrupts_timer0); fflush(stdout);
85    #endif
86    }
87    
88    
89    DEVICE_TICK(8253)
90  {  {
91          struct pit8253_data *d = (struct pit8253_data *) extra;          struct pit8253_data *d = (struct pit8253_data *) extra;
92    
93          if (!d->in_use)          if (!d->in_use)
94                  return;                  return;
95    
96          cpu_interrupt(cpu, d->irq_nr);          switch (d->mode[0] & 0x0e) {
97    
98            case I8253_TIMER_INTTC:
99                    if (d->pending_interrupts_timer0 > 0)
100                            cpu_interrupt(cpu, d->irq0_nr);
101                    break;
102    
103            case I8253_TIMER_SQWAVE:
104            case I8253_TIMER_RATEGEN:
105                    break;
106    
107            default:fatal("[ 8253: unimplemented mode 0x%x ]\n", d->mode[0] & 0x0e);
108                    exit(1);
109            }
110  }  }
111    
112    
113  /*  DEVICE_ACCESS(8253)
  *  dev_8253_access():  
  */  
 int dev_8253_access(struct cpu *cpu, struct memory *mem,  
         uint64_t relative_addr, unsigned char *data, size_t len,  
         int writeflag, void *extra)  
114  {  {
115          struct pit8253_data *d = (struct pit8253_data *) extra;          struct pit8253_data *d = (struct pit8253_data *) extra;
116          uint64_t idata = 0, odata = 0;          uint64_t idata = 0, odata = 0;
# Line 85  int dev_8253_access(struct cpu *cpu, str Line 120  int dev_8253_access(struct cpu *cpu, str
120    
121          d->in_use = 1;          d->in_use = 1;
122    
         /*  TODO: ack somewhere else  */  
         cpu_interrupt_ack(cpu, d->irq_nr);  
   
123          switch (relative_addr) {          switch (relative_addr) {
124          case 0x00:  
125            case I8253_TIMER_CNTR0:
126            case I8253_TIMER_CNTR1:
127            case I8253_TIMER_CNTR2:
128                  if (writeflag == MEM_WRITE) {                  if (writeflag == MEM_WRITE) {
129                          /*  TODO  */                          switch (d->mode_byte & 0x30) {
130                            case I8253_TIMER_LSB:
131                            case I8253_TIMER_16BIT:
132                                    d->counter[relative_addr] &= 0xff00;
133                                    d->counter[relative_addr] |= (idata & 0xff);
134                                    break;
135                            case I8253_TIMER_MSB:
136                                    d->counter[relative_addr] &= 0x00ff;
137                                    d->counter[relative_addr] |= ((idata&0xff)<<8);
138                                    if (d->counter[relative_addr] != 0)
139                                            d->hz[relative_addr] =
140                                                I8253_TIMER_FREQ / (float)
141                                                d->counter[relative_addr] + 0.5;
142                                    else
143                                            d->hz[relative_addr] = 0;
144                                    debug("[ 8253: counter %i set to %i (%i Hz) "
145                                        "]\n", relative_addr, d->counter[
146                                        relative_addr], d->hz[relative_addr]);
147                                    switch (relative_addr) {
148                                    case 0: if (d->timer0 == NULL)
149                                                    d->timer0 = timer_add(
150                                                        d->hz[0], timer0_tick, d);
151                                            else
152                                                    timer_update_frequency(
153                                                        d->timer0, d->hz[0]);
154                                            break;
155                                    case 1: fatal("TODO: DMA refresh?\n");
156                                            exit(1);
157                                    case 2: fatal("TODO: 8253 tone generation?\n");
158                                            break;
159                                    }
160                                    break;
161                            default:fatal("[ 8253: huh? writing to counter"
162                                        " %i but neither from msb nor lsb? ]\n",
163                                        relative_addr);
164                            }
165                  } else {                  } else {
166                          /*  TODO  */                          switch (d->mode_byte & 0x30) {
167                          /*  odata = 1;  */                          case I8253_TIMER_LSB:
168                          odata = random();                          case I8253_TIMER_16BIT:
169                                    odata = d->counter[relative_addr] & 0xff;
170                                    break;
171                            case I8253_TIMER_MSB:
172                                    odata = (d->counter[relative_addr] >> 8) & 0xff;
173                                    break;
174                            default:fatal("[ 8253: huh? reading from counter"
175                                        " %i but neither from msb nor lsb? ]\n",
176                                        relative_addr);
177                            }
178                  }                  }
179    
180                    /*  Switch from LSB to MSB, if accessing as 16-bit word:  */
181                    if ((d->mode_byte & 0x30) == I8253_TIMER_16BIT)
182                            d->mode_byte &= ~I8253_TIMER_LSB;
183    
184                  break;                  break;
185          case 0x03:  
186            case I8253_TIMER_MODE:
187                  if (writeflag == MEM_WRITE) {                  if (writeflag == MEM_WRITE) {
188                            d->mode_byte = idata;
189    
190                          d->counter_select = idata >> 6;                          d->counter_select = idata >> 6;
191                          /*  TODO: other bits  */                          if (d->counter_select > 2) {
192                                    debug("[ 8253: attempt to select counter 3,"
193                                        " which doesn't exist. ]\n");
194                                    d->counter_select = 0;
195                            }
196    
197                            d->mode[d->counter_select] = idata & 0x0e;
198    
199                            debug("[ 8253: select=%i mode=0x%x ",
200                                d->counter_select, d->mode[d->counter_select]);
201                            if (idata & 0x30) {
202                                    switch (idata & 0x30) {
203                                    case I8253_TIMER_LSB:
204                                            debug("LSB ");
205                                            break;
206                                    case I8253_TIMER_16BIT:
207                                            debug("LSB+");
208                                    case I8253_TIMER_MSB:
209                                            debug("MSB ");
210                                    }
211                            }
212                            debug("]\n");
213    
214                            if (idata & I8253_TIMER_BCD) {
215                                    fatal("[ 8253: BCD not yet implemented ]\n");
216                                    exit(1);
217                            }
218                  } else {                  } else {
219                          odata = d->counter_select << 6;                          debug("[ 8253: read; can this actually happen? ]\n");
220                            odata = d->mode_byte;
221                  }                  }
222                  break;                  break;
223          default:  
224                  if (writeflag == MEM_WRITE) {          default:if (writeflag == MEM_WRITE) {
225                          fatal("[ 8253: unimplemented write to address 0x%x"                          fatal("[ 8253: unimplemented write to address 0x%x"
226                              " data=0x%02x ]\n", (int)relative_addr, (int)idata);                              " data=0x%02x ]\n", (int)relative_addr, (int)idata);
227                  } else {                  } else {
228                          fatal("[ 8253: unimplemented read from address 0x%x "                          fatal("[ 8253: unimplemented read from address 0x%x "
229                              "]\n", (int)relative_addr);                              "]\n", (int)relative_addr);
230                  }                  }
231                    exit(1);
232          }          }
233    
234          if (writeflag == MEM_READ)          if (writeflag == MEM_READ)
# Line 123  int dev_8253_access(struct cpu *cpu, str Line 238  int dev_8253_access(struct cpu *cpu, str
238  }  }
239    
240    
241  /*  DEVINIT(8253)
  *  devinit_8253():  
  */  
 int devinit_8253(struct devinit *devinit)  
242  {  {
243          struct pit8253_data *d = malloc(sizeof(struct pit8253_data));          struct pit8253_data *d = malloc(sizeof(struct pit8253_data));
244    
# Line 135  int devinit_8253(struct devinit *devinit Line 247  int devinit_8253(struct devinit *devinit
247                  exit(1);                  exit(1);
248          }          }
249          memset(d, 0, sizeof(struct pit8253_data));          memset(d, 0, sizeof(struct pit8253_data));
250          d->irq_nr = devinit->irq_nr;          d->irq0_nr = devinit->irq_nr;
251          d->in_use = devinit->in_use;          d->in_use = devinit->in_use;
252    
253            /*  Don't cause interrupt, by default.  */
254            d->mode[0] = I8253_TIMER_RATEGEN;
255            d->mode[1] = I8253_TIMER_RATEGEN;
256            d->mode[2] = I8253_TIMER_RATEGEN;
257    
258            devinit->machine->isa_pic_data.pending_timer_interrupts =
259                &d->pending_interrupts_timer0;
260    
261          memory_device_register(devinit->machine->memory, devinit->name,          memory_device_register(devinit->machine->memory, devinit->name,
262              devinit->addr, DEV_8253_LENGTH, dev_8253_access, (void *)d,              devinit->addr, DEV_8253_LENGTH, dev_8253_access, (void *)d,
263              DM_DEFAULT, NULL);              DM_DEFAULT, NULL);
264    
265          machine_add_tickfunction(devinit->machine, dev_8253_tick,          machine_add_tickfunction(devinit->machine, dev_8253_tick,
266              d, TICK_SHIFT);              d, TICK_SHIFT, 0.0);
267    
268          return 1;          return 1;
269  }  }

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

  ViewVC Help
Powered by ViewVC 1.1.26