/[gxemul]/upstream/0.3.8/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

Contents of /upstream/0.3.8/src/devices/dev_8259.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 23 - (show annotations)
Mon Oct 8 16:19:43 2007 UTC (16 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 7770 byte(s)
0.3.8
1 /*
2 * Copyright (C) 2005-2006 Anders Gavare. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 *
28 * $Id: dev_8259.c,v 1.24 2006/02/09 20:02:58 debug Exp $
29 *
30 * 8259 Programmable Interrupt Controller.
31 *
32 * See the following URL for more details:
33 * http://www.nondot.org/sabre/os/files/MiscHW/8259pic.txt
34 */
35
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39
40 #include "cpu.h"
41 #include "device.h"
42 #include "devices.h"
43 #include "emul.h"
44 #include "machine.h"
45 #include "memory.h"
46 #include "misc.h"
47
48
49 #define DEV_8259_LENGTH 2
50
51 /* #define DEV_8259_DEBUG */
52
53
54 /*
55 * dev_8259_access():
56 */
57 DEVICE_ACCESS(8259)
58 {
59 struct pic8259_data *d = (struct pic8259_data *) extra;
60 uint64_t idata = 0, odata = 0;
61 int i;
62
63 if (writeflag == MEM_WRITE)
64 idata = memory_readmax64(cpu, data, len);
65
66 #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) {
75 case 0x00:
76 if (writeflag == MEM_WRITE) {
77 if ((idata & 0x10) == 0x10) {
78 /* Bit 3: 0=edge, 1=level */
79 if (idata & 0x08)
80 fatal("[ 8259: TODO: Level "
81 "triggered (MCA bus) ]\n");
82 if (idata & 0x04)
83 fatal("[ 8259: WARNING: Bit 2 set ]\n");
84 /* Bit 1: 0=cascade, 1=single */
85 /* Bit 0: 1=4th init byte */
86 /* This happens on non-x86 systems:
87 if (!(idata & 0x01))
88 fatal("[ 8259: WARNING: Bit 0 NOT set!"
89 "!! ]\n"); */
90 d->init_state = 1;
91 break;
92 }
93
94 /* TODO: Is it ok to abort init state when there
95 is a non-init command? */
96 if (d->init_state)
97 fatal("[ 8259: WARNING: Was in init-state, but"
98 " it was aborted? ]\n");
99 d->init_state = 0;
100
101 if (idata == 0x0a) {
102 d->current_command = 0x0a;
103 } else if (idata == 0x0b) {
104 d->current_command = 0x0b;
105 } else if (idata == 0x0c) {
106 /* 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;
113 d->isr = 0;
114 /* Recalculate interrupt assertions,
115 if necessary: */
116 if ((old_irr & ~d->ier) != (d->irr & ~d->ier))
117 cpu_interrupt(cpu, d->irq_nr);
118 } else if ((idata >= 0x21 && idata <= 0x27) ||
119 (idata >= 0x60 && idata <= 0x67) ||
120 (idata >= 0xe0 && idata <= 0xe7)) {
121 /* Specific EOI */
122 int old_irr = d->irr;
123 d->irr &= ~(1 << (idata & 7));
124 d->isr &= ~(1 << (idata & 7));
125 /* Recalc. int assertions, if necessary: */
126 if ((old_irr & ~d->ier) != (d->irr & ~d->ier))
127 cpu_interrupt(cpu, d->irq_nr);
128 } else if (idata == 0x68) {
129 /* Set Special Mask Mode */
130 /* TODO */
131 } else if (idata >= 0xc0 && idata <= 0xc7) {
132 /* Set IRQ Priority Order */
133 /* TODO */
134 } else {
135 fatal("[ 8259: unimplemented command 0x%02x"
136 " ]\n", (int)idata);
137 cpu->running = 0;
138 }
139 } else {
140 switch (d->current_command) {
141 case 0x0a:
142 odata = d->irr;
143 break;
144 case 0x0b:
145 odata = d->isr;
146 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:
157 odata = 0x00;
158 for (i=0; i<8; i++)
159 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;
179 case 0x01:
180 if (d->init_state > 0) {
181 if (d->init_state == 1) {
182 d->irq_base = idata & 0xf8;
183 /* This happens on non-x86 machines:
184 if (idata & 7)
185 fatal("[ 8259: WARNING! Lowest"
186 " bits in Init Cmd 1 are"
187 " non-zero! ]\n"); */
188 d->init_state = 2;
189 } else if (d->init_state == 2) {
190 /* Slave attachment. TODO */
191 d->init_state = 3;
192 } else if (d->init_state == 3) {
193 if (idata & 0x02) {
194 /* 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");
198 }
199 if (!(idata & 0x01))
200 fatal("[ 8259: WARNING! Bit 0 "
201 "in Init Cmd 4 is not"
202 " set! ]\n");
203 d->init_state = 0;
204 }
205 break;
206 }
207
208 if (writeflag == MEM_WRITE) {
209 int old_ier = d->ier;
210 d->ier = idata;
211
212 /* 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 {
217 odata = d->ier;
218 }
219 break;
220 default:
221 if (writeflag == MEM_WRITE) {
222 fatal("[ 8259: unimplemented write to address 0x%x"
223 " data=0x%02x ]\n", (int)relative_addr, (int)idata);
224 cpu->running = 0;
225 } else {
226 fatal("[ 8259: unimplemented read from address 0x%x "
227 "]\n", (int)relative_addr);
228 cpu->running = 0;
229 }
230 }
231
232 if (writeflag == MEM_READ)
233 memory_writemax64(cpu, data, len, odata);
234
235 return 1;
236 }
237
238
239 /*
240 * 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 DEVINIT(8259)
253 {
254 struct pic8259_data *d = malloc(sizeof(struct pic8259_data));
255 char *name2;
256 size_t nlen = strlen(devinit->name) + 20;
257
258 if (d == NULL) {
259 fprintf(stderr, "out of memory\n");
260 exit(1);
261 }
262 memset(d, 0, sizeof(struct pic8259_data));
263 d->irq_nr = devinit->irq_nr;
264
265 name2 = malloc(nlen);
266 snprintf(name2, nlen, "%s", devinit->name);
267 if ((devinit->addr & 0xfff) == 0xa0) {
268 strlcat(name2, " [secondary]", nlen);
269 d->irq_base = 8;
270 }
271
272 memory_device_register(devinit->machine->memory, name2,
273 devinit->addr, DEV_8259_LENGTH, dev_8259_access, d,
274 DM_DEFAULT, NULL);
275
276 devinit->return_ptr = d;
277 return 1;
278 }
279

  ViewVC Help
Powered by ViewVC 1.1.26