interrupt.cc Source File

Back to the index.

interrupt.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2006-2009 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  * The interrupt subsystem.
29  *
30  * Interrupts have a "path", e.g. "machine[0].cpu.5". A device which
31  * wishes to cause this interrupt needs to connect to it.
32  *
33  * The possible interrupt paths are registered by CPUs, interrupt controllers,
34  * etc., that have a way of receiving interrupt requests. The physical
35  * version of an interrupt path is usually a "pin" on the CPU, or similar.
36  *
37  * Once connected, the interrupt can be asserted or deasserted.
38  *
39  * For examples on how it is used, see the various devices in src/devices/.
40  */
41 
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 
46 #include "interrupt.h"
47 #include "misc.h"
48 
49 
50 /* #define INTERRUPT_DEBUG */
51 
52 
54  struct interrupt templ;
57 };
58 
59 
60 static int nr_of_interrupt_handlers = 0;
61 static struct interrupt_handler *interrupt_handlers = NULL;
62 
63 
64 /*
65  * Dummy interrupt assert/deassert for "no interrupt" interrupts:
66  */
67 static void no_interrupt_assert(struct interrupt *i) { }
68 static void no_interrupt_deassert(struct interrupt *i) { }
69 
70 
71 /*
72  * interrupt_handler_register():
73  *
74  * Add an interrupt handler to the interrupt subsystem. The template
75  * needs to have all members set.
76  *
77  * Name is of the form "machine[0].cpu[0].irq[3].isa[14]" etc.
78  *
79  * If there already is a handler with this name, the emulator aborts.
80  */
82 {
83  int i;
84 
85 #ifdef INTERRUPT_DEBUG
86  printf("interrupt_handler_register(\"%s\")\n", templ->name);
87 #endif
88 
89  /* See if the name is already registered: */
90  for (i=0; i<nr_of_interrupt_handlers; i++) {
91  if (strcmp(templ->name,
92  interrupt_handlers[i].templ.name) != 0)
93  continue;
94 
95  fatal("\ninterrupt_handler_register(): An interrupt handler"
96  " using the name '%s' is already registered.\n",
97  templ->name);
98  exit(1);
99  }
100 
101  nr_of_interrupt_handlers ++;
102  CHECK_ALLOCATION(interrupt_handlers =
103  (struct interrupt_handler *) realloc(interrupt_handlers,
104  nr_of_interrupt_handlers * sizeof(struct interrupt_handler)));
105 
106  interrupt_handlers[nr_of_interrupt_handlers-1].templ = *templ;
107  CHECK_ALLOCATION(interrupt_handlers[nr_of_interrupt_handlers-1].
108  templ.name = strdup(templ->name));
109 }
110 
111 
112 /*
113  * interrupt_handler_remove():
114  *
115  * Remove an interrupt handler from the interrupt subsystem. If there are
116  * still connected users of this interrupt, then an error message is printed
117  * and the emulator aborts.
118  */
119 void interrupt_handler_remove(const char *name)
120 {
121  int i;
122 
123 #ifdef INTERRUPT_DEBUG
124  printf("interrupt_handler_remove(\"%s\")\n", name);
125 #endif
126 
127  for (i=0; i<nr_of_interrupt_handlers; i++) {
128  if (strcmp(name, interrupt_handlers[i].templ.name) != 0)
129  continue;
130 
131  /*
132  * Remove handler i, and return:
133  */
134  if (interrupt_handlers[i].nr_of_exclusive_users > 0 ||
135  interrupt_handlers[i].nr_of_nonexclusive_users > 0) {
136  fatal("interrupt_handler_remove(): Attempt to "
137  "remove interrupt handler '%s' which has %i "
138  "exclusive and %i non-exclusive users. Aborting.\n",
139  name, interrupt_handlers[i].nr_of_exclusive_users,
140  interrupt_handlers[i].nr_of_nonexclusive_users);
141  exit(1);
142  }
143 
144  if (i != nr_of_interrupt_handlers-1)
145  memcpy(&interrupt_handlers[i],
146  &interrupt_handlers[i + 1],
147  nr_of_interrupt_handlers - i - 1);
148 
149  nr_of_interrupt_handlers --;
150 
151  return;
152  }
153 
154  fatal("interrupt_handler_remove(): '%s' not found? Aborting.\n", name);
155  exit(1);
156 }
157 
158 
159 /*
160  * interrupt_handler_lookup():
161  *
162  * Scans the list of registered interrupt handlers for a given name. If the
163  * name is found, the template is filled with valid data, and 1 is returned.
164  * If the name is not found, 0 is returned.
165  */
166 int interrupt_handler_lookup(const char *name, struct interrupt *templ)
167 {
168  int i;
169 
170 #ifdef INTERRUPT_DEBUG
171  printf("interrupt_handler_lookup(\"%s\")\n", name);
172 #endif
173 
174  if (name[0] == '\0') {
175  /* No interrupt: */
176  memset(templ, 0, sizeof(struct interrupt));
177  templ->interrupt_assert = no_interrupt_assert;
178  templ->interrupt_deassert = no_interrupt_deassert;
179  }
180 
181  for (i=0; i<nr_of_interrupt_handlers; i++) {
182  if (strcmp(name, interrupt_handlers[i].templ.name) != 0)
183  continue;
184 
185  *templ = interrupt_handlers[i].templ;
186  return 1;
187  }
188 
189  /* The 'if' is an ugly hack to prevent a Compaq CC warning. */
190  if (i >= nr_of_interrupt_handlers) {
191  printf("interrupt_handler_lookup(\"%s\") failed. "
192  "Aborting.\n", name);
193  abort();
194  }
195 
196  return 0;
197 }
198 
199 
200 /*
201  * interrupt_connect():
202  *
203  * Increases the exclusive or nonexclusive nr or users of an interrupt.
204  */
205 void interrupt_connect(struct interrupt *in, int exclusive)
206 {
207  int i;
208 
209 #ifdef INTERRUPT_DEBUG
210  printf("interrupt_connect(\"%s\")\n", in->name);
211 #endif
212 
213  if (in->name == NULL || in->name[0] == '\0')
214  return;
215 
216  for (i=0; i<nr_of_interrupt_handlers; i++) {
217  if (strcmp(in->name, interrupt_handlers[i].templ.name) != 0)
218  continue;
219 
220  if (exclusive) {
221  interrupt_handlers[i].nr_of_exclusive_users ++;
222  if (interrupt_handlers[i].nr_of_exclusive_users > 1) {
223  fatal("Fatal error in interrupt_connect(): "
224  "more than 1 exclusive user. Dumping "
225  "core for backtrace.\n");
226  abort();
227  }
228  } else {
229  interrupt_handlers[i].nr_of_nonexclusive_users ++;
230  }
231 
232  return;
233  }
234 
235  fatal("Internal error in interrupt_connect(): name '%s' not "
236  "found? Dumping core for debugging.\n", in->name);
237  abort();
238 }
239 
240 
241 /*
242  * interrupt_disconnect():
243  *
244  * Decreases the exclusive or nonexclusive nr or users of an interrupt.
245  */
246 void interrupt_disconnect(struct interrupt *in, int exclusive)
247 {
248  int i;
249 
250  if (in->name == NULL || in->name[0] == '\0')
251  return;
252 
253  for (i=0; i<nr_of_interrupt_handlers; i++) {
254  if (strcmp(in->name, interrupt_handlers[i].templ.name) != 0)
255  continue;
256 
257  if (exclusive) {
258  interrupt_handlers[i].nr_of_exclusive_users --;
259  if (interrupt_handlers[i].nr_of_exclusive_users < 0) {
260  fatal("Fatal error in interrupt_disconnect():"
261  "nr of exclusive users < 0?\n");
262  exit(1);
263  }
264  } else {
265  interrupt_handlers[i].nr_of_nonexclusive_users --;
266  if (interrupt_handlers[i].nr_of_nonexclusive_users<0) {
267  fatal("Fatal error in interrupt_disconnect():"
268  "nr of non-exclusive users < 0?\n");
269  exit(1);
270  }
271  }
272 
273  return;
274  }
275 
276  fatal("Internal error in interrupt_disconnect(): name '%s' not "
277  "found?\n", in->name);
278  exit(1);
279 }
280 
281 
void fatal(const char *fmt,...)
Definition: main.cc:152
void(* interrupt_assert)(struct interrupt *)
Definition: interrupt.h:38
int nr_of_nonexclusive_users
Definition: interrupt.cc:56
void(* interrupt_deassert)(struct interrupt *)
Definition: interrupt.h:39
int nr_of_exclusive_users
Definition: interrupt.cc:55
#define CHECK_ALLOCATION(ptr)
Definition: misc.h:239
void interrupt_handler_remove(const char *name)
Definition: interrupt.cc:119
int interrupt_handler_lookup(const char *name, struct interrupt *templ)
Definition: interrupt.cc:166
void interrupt_connect(struct interrupt *in, int exclusive)
Definition: interrupt.cc:205
void interrupt_handler_register(struct interrupt *templ)
Definition: interrupt.cc:81
char * name
Definition: interrupt.h:66
struct interrupt templ
Definition: interrupt.cc:54
void interrupt_disconnect(struct interrupt *in, int exclusive)
Definition: interrupt.cc:246

Generated on Sun Sep 30 2018 16:05:18 for GXemul by doxygen 1.8.13