]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - sim/mips/dv-tx3904irc.c
Only enable H/W on some mips targets.
[thirdparty/binutils-gdb.git] / sim / mips / dv-tx3904irc.c
1 /* This file is part of the program GDB, the GNU debugger.
2
3 Copyright (C) 1998 Free Software Foundation, Inc.
4 Contributed by Cygnus Solutions.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19
20 */
21
22
23 #include "sim-main.h"
24 #include "hw-base.h"
25
26
27 /* DEVICE
28
29
30 tx3904irc - tx3904 interrupt controller
31
32
33 DESCRIPTION
34
35
36 Implements the tx3904 interrupt controller described in the tx3904
37 user guide. It does not include the interrupt detection circuit
38 that preprocesses the eight external interrupts.
39
40
41 PROPERTIES
42
43
44 reg <base> <length>
45
46 Base of IRC control register bank. <length> must equal 0x20.
47 Registers offsets: 0: ISR: interrupt status register
48 4: IMR: interrupt mask register
49 16: ILR0: interrupt level register 3..0
50 20: ILR1: interrupt level register 7..4
51 24: ILR2: interrupt level register 11..8
52 28: ILR3: interrupt level register 15..12
53
54
55
56 PORTS
57
58
59 ip (output)
60
61 Interrupt priority port. An event is generated when an interrupt
62 of a sufficient priority is passed through the IRC. The value
63 associated with the event is the interrupt level (16-31), as given
64 for bits IP[5:0] in the book TMPR3904F Rev. 2.0, pg. 11-3. Note
65 that even though INT[0] is tied externally to IP[5], we simulate
66 it as passing through the controller.
67
68
69 int0-7 (input)
70
71 External interrupts.
72
73
74 dmac0-3 (input)
75
76 DMA internal interrupts, correspond to DMA channels 0-3.
77
78
79 sio0-1 (input)
80
81 SIO internal interrupts.
82
83
84 tmr0-2 (input)
85
86 Timer internal interrupts.
87
88 */
89
90
91
92 /* port ID's */
93
94 enum {
95 /* inputs, ordered to correspond to interrupt sources 0..15 */
96 INT1_PORT = 0, INT2_PORT, INT3_PORT, INT4_PORT, INT5_PORT, INT6_PORT, INT7_PORT,
97 DMAC3_PORT, DMAC2_PORT, DMAC1_PORT, DMAC0_PORT, SIO0_PORT, SIO1_PORT,
98 TMR0_PORT, TMR1_PORT, TMR2_PORT,
99
100 /* special INT[0] port */
101 INT0_PORT,
102
103 /* reset */
104 RESET_PORT,
105
106 /* output */
107 IP_PORT
108 };
109
110
111 /* register numbers; each is one word long */
112 enum {
113 ISR_REG = 0,
114 IMR_REG = 1,
115 ILR0_REG = 4,
116 ILR1_REG = 5,
117 ILR2_REG = 6,
118 ILR3_REG = 7,
119 };
120
121
122
123 static const struct hw_port_descriptor tx3904irc_ports[] = {
124
125 /* interrupt output */
126
127 { "ip", IP_PORT, 0, output_port, },
128
129 /* interrupt inputs (as names) */
130 /* in increasing order of level number */
131
132 { "int1", INT1_PORT, 0, input_port, },
133 { "int2", INT2_PORT, 0, input_port, },
134 { "int3", INT3_PORT, 0, input_port, },
135 { "int4", INT4_PORT, 0, input_port, },
136 { "int5", INT5_PORT, 0, input_port, },
137 { "int6", INT6_PORT, 0, input_port, },
138 { "int7", INT7_PORT, 0, input_port, },
139
140 { "dmac3", DMAC3_PORT, 0, input_port, },
141 { "dmac2", DMAC2_PORT, 0, input_port, },
142 { "dmac1", DMAC1_PORT, 0, input_port, },
143 { "dmac0", DMAC0_PORT, 0, input_port, },
144
145 { "sio0", SIO0_PORT, 0, input_port, },
146 { "sio1", SIO1_PORT, 0, input_port, },
147
148 { "tmr0", TMR0_PORT, 0, input_port, },
149 { "tmr1", TMR1_PORT, 0, input_port, },
150 { "tmr2", TMR2_PORT, 0, input_port, },
151
152 { "reset", RESET_PORT, 0, input_port, },
153 { "int0", INT0_PORT, 0, input_port, },
154
155 { NULL, },
156 };
157
158
159 #define NR_SOURCES (TMR3_PORT - INT1_PORT + 1) /* 16: number of interrupt sources */
160
161
162 /* The interrupt controller register internal state. Note that we
163 store state using the control register images, in host endian
164 order. */
165
166 struct tx3904irc {
167 address_word base_address; /* control register base */
168 unsigned_4 isr;
169 #define ISR_SET(c,s) ((c)->isr &= ~ (1 << (s)))
170 unsigned_4 imr;
171 #define IMR_GET(c) ((c)->imr)
172 unsigned_4 ilr[4];
173 #define ILR_GET(c,s) LSEXTRACTED32((c)->ilr[(s)/4], (s) % 4 * 8 + 2, (s) % 4 * 8)
174 };
175
176
177
178 /* Finish off the partially created hw device. Attach our local
179 callbacks. Wire up our port names etc */
180
181 static hw_io_read_buffer_callback tx3904irc_io_read_buffer;
182 static hw_io_write_buffer_callback tx3904irc_io_write_buffer;
183 static hw_port_event_callback tx3904irc_port_event;
184
185 static void
186 attach_tx3904irc_regs (struct hw *me,
187 struct tx3904irc *controller)
188 {
189 unsigned_word attach_address;
190 int attach_space;
191 unsigned attach_size;
192 reg_property_spec reg;
193
194 if (hw_find_property (me, "reg") == NULL)
195 hw_abort (me, "Missing \"reg\" property");
196
197 if (!hw_find_reg_array_property (me, "reg", 0, &reg))
198 hw_abort (me, "\"reg\" property must contain one addr/size entry");
199
200 hw_unit_address_to_attach_address (hw_parent (me),
201 &reg.address,
202 &attach_space,
203 &attach_address,
204 me);
205 hw_unit_size_to_attach_size (hw_parent (me),
206 &reg.size,
207 &attach_size, me);
208
209 hw_attach_address (hw_parent (me), 0,
210 attach_space, attach_address, attach_size,
211 me);
212
213 controller->base_address = attach_address;
214 }
215
216
217 static void
218 tx3904irc_finish (struct hw *me)
219 {
220 struct tx3904irc *controller;
221
222 controller = HW_ZALLOC (me, struct tx3904irc);
223 set_hw_data (me, controller);
224 set_hw_io_read_buffer (me, tx3904irc_io_read_buffer);
225 set_hw_io_write_buffer (me, tx3904irc_io_write_buffer);
226 set_hw_ports (me, tx3904irc_ports);
227 set_hw_port_event (me, tx3904irc_port_event);
228
229 /* Attach ourself to our parent bus */
230 attach_tx3904irc_regs (me, controller);
231
232 /* Initialize to reset state */
233 controller->isr = 0x0000ffff;
234 controller->imr = 0;
235 controller->ilr[0] =
236 controller->ilr[1] =
237 controller->ilr[2] =
238 controller->ilr[3] = 0;
239 }
240
241
242
243 /* An event arrives on an interrupt port */
244
245 static void
246 tx3904irc_port_event (struct hw *me,
247 int my_port,
248 struct hw *source,
249 int source_port,
250 int level)
251 {
252 struct tx3904irc *controller = hw_data (me);
253
254 switch (my_port)
255 {
256 case INT0_PORT:
257 {
258 int ip_number = 32; /* compute IP[5:0] */
259 HW_TRACE ((me, "port-event INT[0]"));
260 hw_port_event(me, IP_PORT, ip_number);
261 break;
262 }
263
264 case INT1_PORT: case INT2_PORT: case INT3_PORT: case INT4_PORT:
265 case INT5_PORT: case INT6_PORT: case INT7_PORT: case DMAC3_PORT:
266 case DMAC2_PORT: case DMAC1_PORT: case DMAC0_PORT: case SIO0_PORT:
267 case SIO1_PORT: case TMR0_PORT: case TMR1_PORT: case TMR2_PORT:
268 {
269 int source = my_port - INT1_PORT;
270
271 HW_TRACE ((me, "port-event interrupt source %d", source));
272 ISR_SET(controller, source);
273 if(ILR_GET(controller, source) > IMR_GET(controller))
274 {
275 int ip_number = 16 + source; /* compute IP[4:0] */
276 HW_TRACE ((me, "interrupt level %ld", ILR_GET(controller,source)));
277 hw_port_event(me, IP_PORT, ip_number);
278 }
279 break;
280 }
281
282 case RESET_PORT:
283 {
284 HW_TRACE ((me, "reset"));
285 controller->isr = 0x0000ffff;
286 controller->imr = 0;
287 controller->ilr[0] =
288 controller->ilr[1] =
289 controller->ilr[2] =
290 controller->ilr[3] = 0;
291 break;
292 }
293
294 case IP_PORT:
295 hw_abort (me, "Event on output port %d", my_port);
296 break;
297
298 default:
299 hw_abort (me, "Event on unknown port %d", my_port);
300 break;
301 }
302 }
303
304
305 /* generic read/write */
306
307 static unsigned
308 tx3904irc_io_read_buffer (struct hw *me,
309 void *dest,
310 int space,
311 unsigned_word base,
312 unsigned nr_bytes)
313 {
314 struct tx3904irc *controller = hw_data (me);
315 unsigned byte;
316
317 HW_TRACE ((me, "read 0x%08lx %d", (long) base, (int) nr_bytes));
318 for (byte = 0; byte < nr_bytes; byte++)
319 {
320 address_word address = base + byte;
321 int reg_number = (address - controller->base_address) / 4;
322 int reg_offset = (address - controller->base_address) % 4;
323 unsigned_4 register_value; /* in target byte order */
324
325 /* fill in entire register_value word */
326 switch (reg_number)
327 {
328 case ISR_REG: register_value = controller->isr; break;
329 case IMR_REG: register_value = controller->imr; break;
330 case ILR0_REG: register_value = controller->ilr[0]; break;
331 case ILR1_REG: register_value = controller->ilr[1]; break;
332 case ILR2_REG: register_value = controller->ilr[2]; break;
333 case ILR3_REG: register_value = controller->ilr[3]; break;
334 default: register_value = 0;
335 }
336
337 /* write requested byte out */
338 memcpy ((char*) dest + byte, ((char*)& register_value)+reg_offset, 1);
339 }
340
341 return nr_bytes;
342 }
343
344
345
346 static unsigned
347 tx3904irc_io_write_buffer (struct hw *me,
348 const void *source,
349 int space,
350 unsigned_word base,
351 unsigned nr_bytes)
352 {
353 struct tx3904irc *controller = hw_data (me);
354 unsigned byte;
355
356 HW_TRACE ((me, "write 0x%08lx %d", (long) base, (int) nr_bytes));
357 for (byte = 0; byte < nr_bytes; byte++)
358 {
359 address_word address = base + byte;
360 int reg_number = (address - controller->base_address) / 4;
361 int reg_offset = (address - controller->base_address) % 4;
362 unsigned_4* register_ptr;
363 unsigned_4 register_value;
364
365 /* fill in entire register_value word */
366 switch (reg_number)
367 {
368 case ISR_REG: register_ptr = & controller->isr; break;
369 case IMR_REG: register_ptr = & controller->imr; break;
370 case ILR0_REG: register_ptr = & controller->ilr[0]; break;
371 case ILR1_REG: register_ptr = & controller->ilr[1]; break;
372 case ILR2_REG: register_ptr = & controller->ilr[2]; break;
373 case ILR3_REG: register_ptr = & controller->ilr[3]; break;
374 default: register_ptr = & register_value; /* used as a dummy */
375 }
376
377 HW_TRACE ((me, "reg %d pre: %08lx", reg_number, (long) *register_ptr));
378
379 /* overwrite requested byte */
380 memcpy (((char*)register_ptr)+reg_offset, (char*)source + byte, 1);
381
382 HW_TRACE ((me, "post: %08lx", (long) *register_ptr));
383 }
384 return nr_bytes;
385 }
386
387
388 const struct hw_device_descriptor dv_tx3904irc_descriptor[] = {
389 { "tx3904irc", tx3904irc_finish, },
390 { NULL },
391 };