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