]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - sim/mips/dv-tx3904irc.c
bbc059b4c48cce0c0509499f68d005453135ac9d
[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, 2007 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-main.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, so assumes that
39 each event on an input interrupt port signals a new interrupt.
40 That is, it implements edge- rather than level-triggered
41 interrupts.
42
43 This implementation does not support multiple concurrent
44 interrupts.
45
46
47 PROPERTIES
48
49
50 reg <base> <length>
51
52 Base of IRC control register bank. <length> must equal 0x20.
53 Registers offsets: 0: ISR: interrupt status register
54 4: IMR: interrupt mask register
55 16: ILR0: interrupt level register 3..0
56 20: ILR1: interrupt level register 7..4
57 24: ILR2: interrupt level register 11..8
58 28: ILR3: interrupt level register 15..12
59
60
61
62 PORTS
63
64
65 ip (output)
66
67 Interrupt priority port. An event is generated when an interrupt
68 of a sufficient priority is passed through the IRC. The value
69 associated with the event is the interrupt level (16-31), as given
70 for bits IP[5:0] in the book TMPR3904F Rev. 2.0, pg. 11-3. Note
71 that even though INT[0] is tied externally to IP[5], we simulate
72 it as passing through the controller.
73
74 An output level of zero signals the clearing of a level interrupt.
75
76
77 int0-7 (input)
78
79 External interrupts. Level = 0 -> level interrupt cleared.
80
81
82 dmac0-3 (input)
83
84 DMA internal interrupts, correspond to DMA channels 0-3. Level = 0 -> level interrupt cleared.
85
86
87 sio0-1 (input)
88
89 SIO internal interrupts. Level = 0 -> level interrupt cleared.
90
91
92 tmr0-2 (input)
93
94 Timer internal interrupts. Level = 0 -> level interrupt cleared.
95
96 */
97
98
99
100
101
102 /* register numbers; each is one word long */
103 enum
104 {
105 ISR_REG = 0,
106 IMR_REG = 1,
107 ILR0_REG = 4,
108 ILR1_REG = 5,
109 ILR2_REG = 6,
110 ILR3_REG = 7,
111 };
112
113
114 /* port ID's */
115
116 enum
117 {
118 /* inputs, ordered to correspond to interrupt sources 0..15 */
119 INT1_PORT = 0, INT2_PORT, INT3_PORT, INT4_PORT, INT5_PORT, INT6_PORT, INT7_PORT,
120 DMAC3_PORT, DMAC2_PORT, DMAC1_PORT, DMAC0_PORT, SIO0_PORT, SIO1_PORT,
121 TMR0_PORT, TMR1_PORT, TMR2_PORT,
122
123 /* special INT[0] port */
124 INT0_PORT,
125
126 /* reset */
127 RESET_PORT,
128
129 /* output */
130 IP_PORT
131 };
132
133
134 static const struct hw_port_descriptor tx3904irc_ports[] = {
135
136 /* interrupt output */
137
138 { "ip", IP_PORT, 0, output_port, },
139
140 /* interrupt inputs (as names) */
141 /* in increasing order of level number */
142
143 { "int1", INT1_PORT, 0, input_port, },
144 { "int2", INT2_PORT, 0, input_port, },
145 { "int3", INT3_PORT, 0, input_port, },
146 { "int4", INT4_PORT, 0, input_port, },
147 { "int5", INT5_PORT, 0, input_port, },
148 { "int6", INT6_PORT, 0, input_port, },
149 { "int7", INT7_PORT, 0, input_port, },
150
151 { "dmac3", DMAC3_PORT, 0, input_port, },
152 { "dmac2", DMAC2_PORT, 0, input_port, },
153 { "dmac1", DMAC1_PORT, 0, input_port, },
154 { "dmac0", DMAC0_PORT, 0, input_port, },
155
156 { "sio0", SIO0_PORT, 0, input_port, },
157 { "sio1", SIO1_PORT, 0, input_port, },
158
159 { "tmr0", TMR0_PORT, 0, input_port, },
160 { "tmr1", TMR1_PORT, 0, input_port, },
161 { "tmr2", TMR2_PORT, 0, input_port, },
162
163 { "reset", RESET_PORT, 0, input_port, },
164 { "int0", INT0_PORT, 0, input_port, },
165
166 { NULL, },
167 };
168
169
170 #define NR_SOURCES (TMR3_PORT - INT1_PORT + 1) /* 16: number of interrupt sources */
171
172
173 /* The interrupt controller register internal state. Note that we
174 store state using the control register images, in host endian
175 order. */
176
177 struct tx3904irc {
178 address_word base_address; /* control register base */
179 unsigned_4 isr;
180 #define ISR_SET(c,s) ((c)->isr &= ~ (1 << (s)))
181 unsigned_4 imr;
182 #define IMR_GET(c) ((c)->imr)
183 unsigned_4 ilr[4];
184 #define ILR_GET(c,s) LSEXTRACTED32((c)->ilr[(s)/4], (s) % 4 * 8 + 2, (s) % 4 * 8)
185 };
186
187
188
189 /* Finish off the partially created hw device. Attach our local
190 callbacks. Wire up our port names etc */
191
192 static hw_io_read_buffer_method tx3904irc_io_read_buffer;
193 static hw_io_write_buffer_method tx3904irc_io_write_buffer;
194 static hw_port_event_method tx3904irc_port_event;
195
196 static void
197 attach_tx3904irc_regs (struct hw *me,
198 struct tx3904irc *controller)
199 {
200 unsigned_word attach_address;
201 int attach_space;
202 unsigned attach_size;
203 reg_property_spec reg;
204
205 if (hw_find_property (me, "reg") == NULL)
206 hw_abort (me, "Missing \"reg\" property");
207
208 if (!hw_find_reg_array_property (me, "reg", 0, &reg))
209 hw_abort (me, "\"reg\" property must contain one addr/size entry");
210
211 hw_unit_address_to_attach_address (hw_parent (me),
212 &reg.address,
213 &attach_space,
214 &attach_address,
215 me);
216 hw_unit_size_to_attach_size (hw_parent (me),
217 &reg.size,
218 &attach_size, me);
219
220 hw_attach_address (hw_parent (me), 0,
221 attach_space, attach_address, attach_size,
222 me);
223
224 controller->base_address = attach_address;
225 }
226
227
228 static void
229 tx3904irc_finish (struct hw *me)
230 {
231 struct tx3904irc *controller;
232
233 controller = HW_ZALLOC (me, struct tx3904irc);
234 set_hw_data (me, controller);
235 set_hw_io_read_buffer (me, tx3904irc_io_read_buffer);
236 set_hw_io_write_buffer (me, tx3904irc_io_write_buffer);
237 set_hw_ports (me, tx3904irc_ports);
238 set_hw_port_event (me, tx3904irc_port_event);
239
240 /* Attach ourself to our parent bus */
241 attach_tx3904irc_regs (me, controller);
242
243 /* Initialize to reset state */
244 controller->isr = 0x0000ffff;
245 controller->imr = 0;
246 controller->ilr[0] =
247 controller->ilr[1] =
248 controller->ilr[2] =
249 controller->ilr[3] = 0;
250 }
251
252
253
254 /* An event arrives on an interrupt port */
255
256 static void
257 tx3904irc_port_event (struct hw *me,
258 int my_port,
259 struct hw *source_dev,
260 int source_port,
261 int level)
262 {
263 struct tx3904irc *controller = hw_data (me);
264
265 /* handle deactivated interrupt */
266 if(level == 0)
267 {
268 HW_TRACE ((me, "interrupt cleared on port %d", my_port));
269 hw_port_event(me, IP_PORT, 0);
270 return;
271 }
272
273 switch (my_port)
274 {
275 case INT0_PORT:
276 {
277 int ip_number = 32; /* compute IP[5:0] */
278 HW_TRACE ((me, "port-event INT[0]"));
279 hw_port_event(me, IP_PORT, ip_number);
280 break;
281 }
282
283 case INT1_PORT: case INT2_PORT: case INT3_PORT: case INT4_PORT:
284 case INT5_PORT: case INT6_PORT: case INT7_PORT: case DMAC3_PORT:
285 case DMAC2_PORT: case DMAC1_PORT: case DMAC0_PORT: case SIO0_PORT:
286 case SIO1_PORT: case TMR0_PORT: case TMR1_PORT: case TMR2_PORT:
287 {
288 int source = my_port - INT1_PORT;
289
290 HW_TRACE ((me, "interrupt asserted on port %d", source));
291 ISR_SET(controller, source);
292 if(ILR_GET(controller, source) > IMR_GET(controller))
293 {
294 int ip_number = 16 + source; /* compute IP[4:0] */
295 HW_TRACE ((me, "interrupt level %d", ILR_GET(controller,source)));
296 hw_port_event(me, IP_PORT, ip_number);
297 }
298 break;
299 }
300
301 case RESET_PORT:
302 {
303 HW_TRACE ((me, "reset"));
304 controller->isr = 0x0000ffff;
305 controller->imr = 0;
306 controller->ilr[0] =
307 controller->ilr[1] =
308 controller->ilr[2] =
309 controller->ilr[3] = 0;
310 break;
311 }
312
313 case IP_PORT:
314 hw_abort (me, "Event on output port %d", my_port);
315 break;
316
317 default:
318 hw_abort (me, "Event on unknown port %d", my_port);
319 break;
320 }
321 }
322
323
324 /* generic read/write */
325
326 static unsigned
327 tx3904irc_io_read_buffer (struct hw *me,
328 void *dest,
329 int space,
330 unsigned_word base,
331 unsigned nr_bytes)
332 {
333 struct tx3904irc *controller = hw_data (me);
334 unsigned byte;
335
336 HW_TRACE ((me, "read 0x%08lx %d", (long) base, (int) nr_bytes));
337 for (byte = 0; byte < nr_bytes; byte++)
338 {
339 address_word address = base + byte;
340 int reg_number = (address - controller->base_address) / 4;
341 int reg_offset = (address - controller->base_address) % 4;
342 unsigned_4 register_value; /* in target byte order */
343
344 /* fill in entire register_value word */
345 switch (reg_number)
346 {
347 case ISR_REG: register_value = controller->isr; break;
348 case IMR_REG: register_value = controller->imr; break;
349 case ILR0_REG: register_value = controller->ilr[0]; break;
350 case ILR1_REG: register_value = controller->ilr[1]; break;
351 case ILR2_REG: register_value = controller->ilr[2]; break;
352 case ILR3_REG: register_value = controller->ilr[3]; break;
353 default: register_value = 0;
354 }
355
356 /* write requested byte out */
357 register_value = H2T_4(register_value);
358 memcpy ((char*) dest + byte, ((char*)& register_value)+reg_offset, 1);
359 }
360
361 return nr_bytes;
362 }
363
364
365
366 static unsigned
367 tx3904irc_io_write_buffer (struct hw *me,
368 const void *source,
369 int space,
370 unsigned_word base,
371 unsigned nr_bytes)
372 {
373 struct tx3904irc *controller = hw_data (me);
374 unsigned byte;
375
376 HW_TRACE ((me, "write 0x%08lx %d", (long) base, (int) nr_bytes));
377 for (byte = 0; byte < nr_bytes; byte++)
378 {
379 address_word address = base + byte;
380 int reg_number = (address - controller->base_address) / 4;
381 int reg_offset = (address - controller->base_address) % 4;
382 unsigned_4* register_ptr;
383 unsigned_4 register_value;
384
385 /* fill in entire register_value word */
386 switch (reg_number)
387 {
388 case ISR_REG: register_ptr = & controller->isr; break;
389 case IMR_REG: register_ptr = & controller->imr; break;
390 case ILR0_REG: register_ptr = & controller->ilr[0]; break;
391 case ILR1_REG: register_ptr = & controller->ilr[1]; break;
392 case ILR2_REG: register_ptr = & controller->ilr[2]; break;
393 case ILR3_REG: register_ptr = & controller->ilr[3]; break;
394 default: register_ptr = & register_value; /* used as a dummy */
395 }
396
397 /* HW_TRACE ((me, "reg %d pre: %08lx", reg_number, (long) *register_ptr)); */
398
399 /* overwrite requested byte */
400 register_value = H2T_4(* register_ptr);
401 memcpy (((char*)&register_value)+reg_offset, (const char*)source + byte, 1);
402 * register_ptr = T2H_4(register_value);
403
404 /* HW_TRACE ((me, "post: %08lx", (long) *register_ptr)); */
405 }
406 return nr_bytes;
407 }
408
409
410 const struct hw_descriptor dv_tx3904irc_descriptor[] = {
411 { "tx3904irc", tx3904irc_finish, },
412 { NULL },
413 };