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

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

revision 6 by dpavlin, Mon Oct 8 16:18:11 2007 UTC revision 22 by dpavlin, Mon Oct 8 16:19:37 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_8259.c,v 1.9 2005/06/02 17:11:35 debug Exp $   *  $Id: dev_8259.c,v 1.24 2006/02/09 20:02:58 debug Exp $
29   *     *  
30   *  8259 Programmable Interrupt Controller.   *  8259 Programmable Interrupt Controller.
31   *   *
32   *  This is mostly bogus. TODO. See the following URL for more details:   *  See the following URL for more details:
33   *      http://www.nondot.org/sabre/os/files/MiscHW/8259pic.txt   *      http://www.nondot.org/sabre/os/files/MiscHW/8259pic.txt
34   */   */
35    
# Line 48  Line 48 
48    
49  #define DEV_8259_LENGTH         2  #define DEV_8259_LENGTH         2
50    
51    /*  #define DEV_8259_DEBUG  */
52    
53    
54  /*  /*
55   *  dev_8259_access():   *  dev_8259_access():
56   */   */
57  int dev_8259_access(struct cpu *cpu, struct memory *mem,  DEVICE_ACCESS(8259)
         uint64_t relative_addr, unsigned char *data, size_t len,  
         int writeflag, void *extra)  
58  {  {
59          struct pic8259_data *d = (struct pic8259_data *) extra;          struct pic8259_data *d = (struct pic8259_data *) extra;
60          uint64_t idata = 0, odata = 0;          uint64_t idata = 0, odata = 0;
61            int i;
62    
63            if (writeflag == MEM_WRITE)
64                    idata = memory_readmax64(cpu, data, len);
65    
66          idata = memory_readmax64(cpu, data, len);  #ifdef DEV_8259_DEBUG
67            if (writeflag == MEM_READ)
68                    fatal("[ 8259: read from 0x%x ]\n", (int)relative_addr);
69            else
70                    fatal("[ 8259: write to 0x%x: 0x%x ]\n",
71                        (int)relative_addr, (int)idata);
72    #endif
73    
74          switch (relative_addr) {          switch (relative_addr) {
75          case 0x00:          case 0x00:
# Line 73  int dev_8259_access(struct cpu *cpu, str Line 83  int dev_8259_access(struct cpu *cpu, str
83                                          fatal("[ 8259: WARNING: Bit 2 set ]\n");                                          fatal("[ 8259: WARNING: Bit 2 set ]\n");
84                                  /*  Bit 1: 0=cascade, 1=single  */                                  /*  Bit 1: 0=cascade, 1=single  */
85                                  /*  Bit 0: 1=4th init byte  */                                  /*  Bit 0: 1=4th init byte  */
86                                  if (!(idata & 0x01))                                  /*  This happens on non-x86 systems:
87                                        if (!(idata & 0x01))
88                                          fatal("[ 8259: WARNING: Bit 0 NOT set!"                                          fatal("[ 8259: WARNING: Bit 0 NOT set!"
89                                              "!! ]\n");                                              "!! ]\n");  */
90                                  d->init_state = 1;                                  d->init_state = 1;
91                                  break;                                  break;
92                          }                          }
# Line 87  int dev_8259_access(struct cpu *cpu, str Line 98  int dev_8259_access(struct cpu *cpu, str
98                                      " it was aborted? ]\n");                                      " it was aborted? ]\n");
99                          d->init_state = 0;                          d->init_state = 0;
100    
101                          switch (idata) {                          if (idata == 0x0a) {
                         case 0x0a:  
102                                  d->current_command = 0x0a;                                  d->current_command = 0x0a;
103                                  break;                          } else if (idata == 0x0b) {
                         case 0x0b:  
104                                  d->current_command = 0x0b;                                  d->current_command = 0x0b;
105                                  break;                          } else if (idata == 0x0c) {
106                          case 0x20:      /*  End Of Interrupt  */                                  /*  Put Master in Buffered Mode  */
107                                    d->current_command = 0x0c;
108                            } else if (idata == 0x20) {
109                                    int old_irr = d->irr;
110                                    /*  End Of Interrupt  */
111                                    /*  TODO: in buffered mode, is this an EOI 0? */
112                                  d->irr &= ~d->isr;                                  d->irr &= ~d->isr;
113                                  d->isr = 0;                                  d->isr = 0;
114                                  /*  Recalculate interrupt assertions:  */                                  /*  Recalculate interrupt assertions,
115                                  cpu_interrupt(cpu, 16);                                      if necessary:  */
116                                  break;                                  if ((old_irr & ~d->ier) != (d->irr & ~d->ier))
117                          case 0x60:                                          cpu_interrupt(cpu, d->irq_nr);
118                          case 0x61:                          } else if ((idata >= 0x21 && idata <= 0x27) ||
119                          case 0x62:                              (idata >= 0x60 && idata <= 0x67) ||
120                          case 0x63:                              (idata >= 0xe0 && idata <= 0xe7)) {
121                          case 0x64:                                  /*  Specific EOI  */
122                          case 0x65:                                  int old_irr = d->irr;
                         case 0x66:  
                         case 0x67:      /*  Specific EOI  */  
123                                  d->irr &= ~(1 << (idata & 7));                                  d->irr &= ~(1 << (idata & 7));
124                                  d->isr &= ~(1 << (idata & 7));                                  d->isr &= ~(1 << (idata & 7));
125                                  /*  Recalculate interrupt assertions:  */                                  /*  Recalc. int assertions, if necessary:  */
126                                  cpu_interrupt(cpu, 16);                                  if ((old_irr & ~d->ier) != (d->irr & ~d->ier))
127                                  break;                                          cpu_interrupt(cpu, d->irq_nr);
128                          case 0x68:      /*  Set Special Mask Mode  */                          } else if (idata == 0x68) {
129                                    /*  Set Special Mask Mode  */
130                                  /*  TODO  */                                  /*  TODO  */
131                                  break;                          } else if (idata >= 0xc0 && idata <= 0xc7) {
132                          case 0xc0:                                  /*  Set IRQ Priority Order  */
                         case 0xc1:  
                         case 0xc2:  
                         case 0xc3:  
                         case 0xc4:  
                         case 0xc5:  
                         case 0xc6:  
                         case 0xc7:      /*  Set IRQ Priority Order  */  
133                                  /*  TODO  */                                  /*  TODO  */
134                                  break;                          } else {
                         default:  
135                                  fatal("[ 8259: unimplemented command 0x%02x"                                  fatal("[ 8259: unimplemented command 0x%02x"
136                                      " ]\n", idata);                                      " ]\n", (int)idata);
137                                  cpu->running = 0;                                  cpu->running = 0;
138                          }                          }
139                  } else {                  } else {
# Line 139  int dev_8259_access(struct cpu *cpu, str Line 144  int dev_8259_access(struct cpu *cpu, str
144                          case 0x0b:                          case 0x0b:
145                                  odata = d->isr;                                  odata = d->isr;
146                                  break;                                  break;
147                            case 0x0c:
148                                    /*  Buffered mode.  */
149                                    odata = 0x00;
150                                    for (i=0; i<8; i++)
151                                            if ((d->irr >> i) & 1) {
152                                                    odata = 0x80 | i;
153                                                    break;
154                                            }
155                                    break;
156                          default:                          default:
157                                  fatal("[ 8259: unimplemented command 0x%02x"                                  odata = 0x00;
158                                      " while reading ]\n", d->current_command);                                  for (i=0; i<8; i++)
159                                  cpu->running = 0;                                          if ((d->irr >> i) & 1) {
160                                                    odata = 0x80 | i;
161                                                    break;
162                                            }
163                                    break;
164                            /*
165                             *  TODO: The "default" label should really do
166                             *  something like this:
167                             *
168                             *      fatal("[ 8259: unimplemented command 0x%02x"
169                             *          " while reading ]\n", d->current_command);
170                             *      cpu->running = 0;
171                             *
172                             *  but Linux seems to read from the secondary PIC
173                             *  in a manner which works better the way things
174                             *  are coded right now.
175                             */
176                          }                          }
177                  }                  }
178                  break;                  break;
# Line 150  int dev_8259_access(struct cpu *cpu, str Line 180  int dev_8259_access(struct cpu *cpu, str
180                  if (d->init_state > 0) {                  if (d->init_state > 0) {
181                          if (d->init_state == 1) {                          if (d->init_state == 1) {
182                                  d->irq_base = idata & 0xf8;                                  d->irq_base = idata & 0xf8;
183                                  if (idata & 7)                                  /*  This happens on non-x86 machines:
184                                        if (idata & 7)
185                                          fatal("[ 8259: WARNING! Lowest"                                          fatal("[ 8259: WARNING! Lowest"
186                                              " bits in Init Cmd 1 are"                                              " bits in Init Cmd 1 are"
187                                              " non-zero! ]\n");                                              " non-zero! ]\n");  */
188                                  d->init_state = 2;                                  d->init_state = 2;
189                          } else if (d->init_state == 2) {                          } else if (d->init_state == 2) {
190                                  /*  Slave attachment. TODO  */                                  /*  Slave attachment. TODO  */
191                                  d->init_state = 3;                                  d->init_state = 3;
192                          } else if (d->init_state == 3) {                          } else if (d->init_state == 3) {
193                                  if (idata & 0x02)                                  if (idata & 0x02) {
194                                          fatal("[ 8259: WARNING! Bit 1 i"                                          /*  Should not be set in PCs, but
195                                                on CATS, for example, it is set.  */
196                                            debug("[ 8259: WARNING! Bit 1 i"
197                                              "n Init Cmd 4 is set! ]\n");                                              "n Init Cmd 4 is set! ]\n");
198                                    }
199                                  if (!(idata & 0x01))                                  if (!(idata & 0x01))
200                                          fatal("[ 8259: WARNING! Bit 0 "                                          fatal("[ 8259: WARNING! Bit 0 "
201                                              "in Init Cmd 4 is not"                                              "in Init Cmd 4 is not"
# Line 172  int dev_8259_access(struct cpu *cpu, str Line 206  int dev_8259_access(struct cpu *cpu, str
206                  }                  }
207    
208                  if (writeflag == MEM_WRITE) {                  if (writeflag == MEM_WRITE) {
209                            int old_ier = d->ier;
210                          d->ier = idata;                          d->ier = idata;
211                          /*  Recalculate interrupt assertions:  */  
212                          cpu_interrupt(cpu, 16);                          /*  Recalculate interrupt assertions,
213                                if necessary:  */
214                            if ((d->irr & ~old_ier) != (d->irr & ~d->ier))
215                                    cpu_interrupt(cpu, d->irq_nr);
216                  } else {                  } else {
217                          odata = d->ier;                          odata = d->ier;
218                  }                  }
# Line 200  int dev_8259_access(struct cpu *cpu, str Line 238  int dev_8259_access(struct cpu *cpu, str
238    
239  /*  /*
240   *  devinit_8259():   *  devinit_8259():
241     *
242     *  Initialize an 8259 PIC. Important notes:
243     *
244     *      x)  Most systems use _TWO_ 8259 PICs. These should be registered
245     *          as separate devices.
246     *
247     *      x)  The irq number specified is the number used to re-calculate
248     *          CPU interrupt assertions.  It is _not_ the irq number at
249     *          which the PIC is connected. (That is left to machine specific
250     *          code in src/machine.c.)
251   */   */
252  int devinit_8259(struct devinit *devinit)  DEVINIT(8259)
253  {  {
254          struct pic8259_data *d = malloc(sizeof(struct pic8259_data));          struct pic8259_data *d = malloc(sizeof(struct pic8259_data));
255          char *name2;          char *name2;
256          int nlen = 40;          size_t nlen = strlen(devinit->name) + 20;
257    
258          if (d == NULL) {          if (d == NULL) {
259                  fprintf(stderr, "out of memory\n");                  fprintf(stderr, "out of memory\n");
# Line 216  int devinit_8259(struct devinit *devinit Line 264  int devinit_8259(struct devinit *devinit
264    
265          name2 = malloc(nlen);          name2 = malloc(nlen);
266          snprintf(name2, nlen, "%s", devinit->name);          snprintf(name2, nlen, "%s", devinit->name);
267          if ((devinit->addr & 0xfff) == 0xa0)          if ((devinit->addr & 0xfff) == 0xa0) {
268                  strcat(name2, " [secondary]");                  strlcat(name2, " [secondary]", nlen);
269                    d->irq_base = 8;
270            }
271    
272          memory_device_register(devinit->machine->memory, name2,          memory_device_register(devinit->machine->memory, name2,
273              devinit->addr, DEV_8259_LENGTH, dev_8259_access, (void *)d,              devinit->addr, DEV_8259_LENGTH, dev_8259_access, d,
274              MEM_DEFAULT, NULL);              DM_DEFAULT, NULL);
275    
276          devinit->return_ptr = d;          devinit->return_ptr = d;
277          return 1;          return 1;

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

  ViewVC Help
Powered by ViewVC 1.1.26