/[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 30 by dpavlin, Mon Oct 8 16:20:40 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.14 2006/07/24 19:08:17 debug Exp $
  *    
  *  8253/8254 Programmable Interval Timer.  
29   *   *
30   *  This is mostly bogus.   *  Intel 8253/8254 Programmable Interval Timer
31     *
32     *  TODO: The timers don't really count down. Fix this when there is a generic
33     *  clock framework; also split counter[] into reset value and current value.
34   */   */
35    
36  #include <stdio.h>  #include <stdio.h>
# Line 44  Line 45 
45  #include "memory.h"  #include "memory.h"
46  #include "misc.h"  #include "misc.h"
47    
48    #include "i8253reg.h"
49    
50    
51    /*  #define debug fatal  */
52    
53  #define DEV_8253_LENGTH         4  #define DEV_8253_LENGTH         4
54  #define TICK_SHIFT              14  #define TICK_SHIFT              14
55    
56    
57  struct pit8253_data {  struct pit8253_data {
         int             irq_nr;  
58          int             in_use;          int             in_use;
59    
60            int             irq0_nr;
61          int             counter_select;          int             counter_select;
62            uint8_t         mode_byte;
63    
64            int             mode[3];
65            int             counter[3];
66  };  };
67    
68    
69  /*  DEVICE_TICK(8253)
  *  dev_8253_tick():  
  */      
 void dev_8253_tick(struct cpu *cpu, void *extra)  
70  {  {
71          struct pit8253_data *d = (struct pit8253_data *) extra;          struct pit8253_data *d = (struct pit8253_data *) extra;
72    
73          if (!d->in_use)          if (!d->in_use)
74                  return;                  return;
75    
76          cpu_interrupt(cpu, d->irq_nr);          switch (d->mode[0] & 0x0e) {
77    
78            case I8253_TIMER_INTTC:
79                    /*  TODO: Correct frequency!  */
80                    cpu_interrupt(cpu, d->irq0_nr);
81                    break;
82    
83            case I8253_TIMER_RATEGEN:
84                    break;
85    
86            default:fatal("[ 8253: unimplemented mode 0x%x ]\n", d->mode[0] & 0x0e);
87                    exit(1);
88            }
89  }  }
90    
91    
92  /*  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)  
93  {  {
94          struct pit8253_data *d = (struct pit8253_data *) extra;          struct pit8253_data *d = (struct pit8253_data *) extra;
95          uint64_t idata = 0, odata = 0;          uint64_t idata = 0, odata = 0;
# Line 86  int dev_8253_access(struct cpu *cpu, str Line 100  int dev_8253_access(struct cpu *cpu, str
100          d->in_use = 1;          d->in_use = 1;
101    
102          /*  TODO: ack somewhere else  */          /*  TODO: ack somewhere else  */
103          cpu_interrupt_ack(cpu, d->irq_nr);          cpu_interrupt_ack(cpu, d->irq0_nr);
104    
105          switch (relative_addr) {          switch (relative_addr) {
106          case 0x00:  
107            case I8253_TIMER_CNTR0:
108            case I8253_TIMER_CNTR1:
109            case I8253_TIMER_CNTR2:
110                  if (writeflag == MEM_WRITE) {                  if (writeflag == MEM_WRITE) {
111                          /*  TODO  */                          switch (d->mode_byte & 0x30) {
112                            case I8253_TIMER_LSB:
113                            case I8253_TIMER_16BIT:
114                                    d->counter[relative_addr] &= 0xff00;
115                                    d->counter[relative_addr] |= (idata & 0xff);
116                                    break;
117                            case I8253_TIMER_MSB:
118                                    d->counter[relative_addr] &= 0x00ff;
119                                    d->counter[relative_addr] |= ((idata&0xff)<<8);
120                                    debug("[ 8253: counter %i set to %i (%i Hz) "
121                                        "]\n", relative_addr, d->counter[
122                                        relative_addr], (int)(I8253_TIMER_FREQ /
123                                        (float)d->counter[relative_addr] + 0.5));
124                                    break;
125                            default:fatal("[ 8253: huh? writing to counter"
126                                        " %i but neither from msb nor lsb? ]\n",
127                                        relative_addr);
128                            }
129                  } else {                  } else {
130                          /*  TODO  */                          switch (d->mode_byte & 0x30) {
131                          /*  odata = 1;  */                          case I8253_TIMER_LSB:
132                          odata = random();                          case I8253_TIMER_16BIT:
133                                    odata = d->counter[relative_addr] & 0xff;
134                                    break;
135                            case I8253_TIMER_MSB:
136                                    odata = (d->counter[relative_addr] >> 8) & 0xff;
137                                    break;
138                            default:fatal("[ 8253: huh? reading from counter"
139                                        " %i but neither from msb nor lsb? ]\n",
140                                        relative_addr);
141                            }
142                  }                  }
143    
144                    /*  Switch from LSB to MSB, if accessing as 16-bit word:  */
145                    if ((d->mode_byte & 0x30) == I8253_TIMER_16BIT)
146                            d->mode_byte &= ~I8253_TIMER_LSB;
147    
148                  break;                  break;
149          case 0x03:  
150            case I8253_TIMER_MODE:
151                  if (writeflag == MEM_WRITE) {                  if (writeflag == MEM_WRITE) {
152                            d->mode_byte = idata;
153    
154                          d->counter_select = idata >> 6;                          d->counter_select = idata >> 6;
155                          /*  TODO: other bits  */                          if (d->counter_select > 2) {
156                                    debug("[ 8253: attempt to select counter 3,"
157                                        " which doesn't exist. ]\n");
158                                    d->counter_select = 0;
159                            }
160    
161                            d->mode[d->counter_select] = idata & 0x0e;
162    
163                            debug("[ 8253: select=%i mode=0x%x ",
164                                d->counter_select, d->mode[d->counter_select]);
165                            if (idata & 0x30) {
166                                    switch (idata & 0x30) {
167                                    case I8253_TIMER_LSB:
168                                            debug("LSB ");
169                                            break;
170                                    case I8253_TIMER_16BIT:
171                                            debug("LSB+");
172                                    case I8253_TIMER_MSB:
173                                            debug("MSB ");
174                                    }
175                            }
176                            debug("]\n");
177    
178                            if (idata & I8253_TIMER_BCD) {
179                                    fatal("[ 8253: BCD not yet implemented ]\n");
180                                    exit(1);
181                            }
182                  } else {                  } else {
183                          odata = d->counter_select << 6;                          debug("[ 8253: read; can this actually happen? ]\n");
184                            odata = d->mode_byte;
185                  }                  }
186                  break;                  break;
187          default:  
188                  if (writeflag == MEM_WRITE) {          default:if (writeflag == MEM_WRITE) {
189                          fatal("[ 8253: unimplemented write to address 0x%x"                          fatal("[ 8253: unimplemented write to address 0x%x"
190                              " data=0x%02x ]\n", (int)relative_addr, (int)idata);                              " data=0x%02x ]\n", (int)relative_addr, (int)idata);
191                  } else {                  } else {
192                          fatal("[ 8253: unimplemented read from address 0x%x "                          fatal("[ 8253: unimplemented read from address 0x%x "
193                              "]\n", (int)relative_addr);                              "]\n", (int)relative_addr);
194                  }                  }
195                    exit(1);
196          }          }
197    
198          if (writeflag == MEM_READ)          if (writeflag == MEM_READ)
# Line 123  int dev_8253_access(struct cpu *cpu, str Line 202  int dev_8253_access(struct cpu *cpu, str
202  }  }
203    
204    
205  /*  DEVINIT(8253)
  *  devinit_8253():  
  */  
 int devinit_8253(struct devinit *devinit)  
206  {  {
207          struct pit8253_data *d = malloc(sizeof(struct pit8253_data));          struct pit8253_data *d = malloc(sizeof(struct pit8253_data));
208    
# Line 135  int devinit_8253(struct devinit *devinit Line 211  int devinit_8253(struct devinit *devinit
211                  exit(1);                  exit(1);
212          }          }
213          memset(d, 0, sizeof(struct pit8253_data));          memset(d, 0, sizeof(struct pit8253_data));
214          d->irq_nr = devinit->irq_nr;          d->irq0_nr = devinit->irq_nr;
215          d->in_use = devinit->in_use;          d->in_use = devinit->in_use;
216    
217            /*  Don't cause interrupt, by default.  */
218            d->mode[0] = I8253_TIMER_RATEGEN;
219            d->mode[1] = I8253_TIMER_RATEGEN;
220            d->mode[2] = I8253_TIMER_RATEGEN;
221    
222          memory_device_register(devinit->machine->memory, devinit->name,          memory_device_register(devinit->machine->memory, devinit->name,
223              devinit->addr, DEV_8253_LENGTH, dev_8253_access, (void *)d,              devinit->addr, DEV_8253_LENGTH, dev_8253_access, (void *)d,
224              DM_DEFAULT, NULL);              DM_DEFAULT, NULL);
225    
226          machine_add_tickfunction(devinit->machine, dev_8253_tick,          machine_add_tickfunction(devinit->machine, dev_8253_tick,
227              d, TICK_SHIFT);              d, TICK_SHIFT, 0.0);
228    
229          return 1;          return 1;
230  }  }

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

  ViewVC Help
Powered by ViewVC 1.1.26