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