1 1.1 christos /* This file is part of the program GDB, the GNU debugger. 2 1.1 christos 3 1.11 christos Copyright (C) 1998-2024 Free Software Foundation, Inc. 4 1.1 christos Contributed by Cygnus Solutions. 5 1.1 christos 6 1.1 christos This program is free software; you can redistribute it and/or modify 7 1.1 christos it under the terms of the GNU General Public License as published by 8 1.1 christos the Free Software Foundation; either version 3 of the License, or 9 1.1 christos (at your option) any later version. 10 1.1 christos 11 1.1 christos This program is distributed in the hope that it will be useful, 12 1.1 christos but WITHOUT ANY WARRANTY; without even the implied warranty of 13 1.1 christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 1.1 christos GNU General Public License for more details. 15 1.1 christos 16 1.1 christos You should have received a copy of the GNU General Public License 17 1.1 christos along with this program. If not, see <http://www.gnu.org/licenses/>. 18 1.1 christos 19 1.1 christos */ 20 1.1 christos 21 1.10 christos /* This must come before any other includes. */ 22 1.10 christos #include "defs.h" 23 1.1 christos 24 1.1 christos #include "sim-main.h" 25 1.1 christos #include "hw-main.h" 26 1.1 christos #include "sim-hw.h" 27 1.1 christos 28 1.1 christos /* DEVICE 29 1.1 christos 30 1.1 christos 31 1.1 christos mn103int - mn103002 interrupt controller 32 1.1 christos 33 1.1 christos 34 1.1 christos DESCRIPTION 35 1.1 christos 36 1.1 christos 37 1.1 christos Implements the mn103002 interrupt controller described in the 38 1.1 christos mn103002 user guide. 39 1.1 christos 40 1.1 christos 41 1.1 christos PROPERTIES 42 1.1 christos 43 1.1 christos 44 1.1 christos reg = <icr-adr> <icr-siz> <iagr-adr> <iadr-siz> <extmd-adr> <extmd-siz> 45 1.1 christos 46 1.1 christos Specify the address of the ICR (total of 30 registers), IAGR and 47 1.1 christos EXTMD registers (within the parent bus). 48 1.1 christos 49 1.1 christos The reg property value `0x34000100 0x7C 0x34000200 0x8 0x3400280 50 1.1 christos 0x8' locates the interrupt controller at the addresses specified in 51 1.1 christos the mn103002 interrupt controller user guide. 52 1.1 christos 53 1.1 christos 54 1.1 christos PORTS 55 1.1 christos 56 1.1 christos 57 1.1 christos nmi (output) 58 1.1 christos 59 1.1 christos Non-maskable interrupt output port. An event on this output ports 60 1.1 christos indicates a NMI request from the interrupt controller. The value 61 1.1 christos attached to the event should be ignored. 62 1.1 christos 63 1.1 christos 64 1.1 christos level (output) 65 1.1 christos 66 1.1 christos Maskable interrupt level output port. An event on this output port 67 1.1 christos indicates a maskable interrupt request at the specified level. The 68 1.1 christos event value defines the level being requested. 69 1.1 christos 70 1.1 christos The interrupt controller will generate an event on this port 71 1.1 christos whenever there is a change to the internal state of the interrupt 72 1.1 christos controller. 73 1.1 christos 74 1.1 christos 75 1.1 christos ack (input) 76 1.1 christos 77 1.1 christos Signal from processor indicating that a maskable interrupt has been 78 1.1 christos accepted and the interrupt controller should latch the IAGR with 79 1.1 christos value of the current highest priority interrupting group. 80 1.1 christos 81 1.1 christos The event value is the interrupt level being accepted by the 82 1.1 christos processor. It should be consistent with the most recent LEVEL sent 83 1.1 christos to the processor from the interrupt controller. 84 1.1 christos 85 1.1 christos 86 1.1 christos int[0..100] (input) 87 1.1 christos 88 1.1 christos Level or edge triggered interrupt input port. Each of the 30 89 1.1 christos groups (0..30) can have up to 4 (0..3) interrupt inputs. The 90 1.1 christos interpretation of a port event/value is determined by the 91 1.1 christos configuration of the corresponding interrupt group. 92 1.1 christos 93 1.1 christos For convenience, numerous aliases to these interrupt inputs are 94 1.1 christos provided. 95 1.1 christos 96 1.1 christos 97 1.1 christos BUGS 98 1.1 christos 99 1.1 christos 100 1.1 christos For edge triggered interrupts, the interrupt controller does not 101 1.1 christos differentiate between POSITIVE (rising) and NEGATIVE (falling) 102 1.1 christos edges. Instead any input port event is considered to be an 103 1.1 christos interrupt trigger. 104 1.1 christos 105 1.1 christos For level sensitive interrupts, the interrupt controller ignores 106 1.1 christos active HIGH/LOW settings and instead always interprets a nonzero 107 1.1 christos port value as an interrupt assertion and a zero port value as a 108 1.1 christos negation. 109 1.1 christos 110 1.1 christos */ 111 1.1 christos 112 1.1 christos 113 1.1 christos /* The interrupt groups - numbered according to mn103002 convention */ 114 1.1 christos 115 1.1 christos enum mn103int_trigger { 116 1.1 christos ACTIVE_LOW, 117 1.1 christos ACTIVE_HIGH, 118 1.1 christos POSITIVE_EDGE, 119 1.1 christos NEGATIVE_EDGE, 120 1.1 christos }; 121 1.1 christos 122 1.1 christos enum mn103int_type { 123 1.1 christos NMI_GROUP, 124 1.1 christos LEVEL_GROUP, 125 1.1 christos }; 126 1.1 christos 127 1.1 christos struct mn103int_group { 128 1.1 christos int gid; 129 1.1 christos int level; 130 1.1 christos unsigned enable; 131 1.1 christos unsigned request; 132 1.1 christos unsigned input; 133 1.1 christos enum mn103int_trigger trigger; 134 1.1 christos enum mn103int_type type; 135 1.1 christos }; 136 1.1 christos 137 1.1 christos enum { 138 1.1 christos FIRST_NMI_GROUP = 0, 139 1.1 christos LAST_NMI_GROUP = 1, 140 1.1 christos FIRST_LEVEL_GROUP = 2, 141 1.1 christos LAST_LEVEL_GROUP = 30, 142 1.1 christos NR_GROUPS, 143 1.1 christos }; 144 1.1 christos 145 1.1 christos enum { 146 1.1 christos LOWEST_LEVEL = 7, 147 1.1 christos }; 148 1.1 christos 149 1.1 christos /* The interrupt controller register address blocks */ 150 1.1 christos 151 1.1 christos struct mn103int_block { 152 1.1 christos unsigned_word base; 153 1.1 christos unsigned_word bound; 154 1.1 christos }; 155 1.1 christos 156 1.1 christos enum { ICR_BLOCK, IAGR_BLOCK, EXTMD_BLOCK, NR_BLOCKS }; 157 1.1 christos 158 1.1 christos 159 1.1 christos struct mn103int { 160 1.1 christos struct mn103int_block block[NR_BLOCKS]; 161 1.1 christos struct mn103int_group group[NR_GROUPS]; 162 1.1 christos unsigned interrupt_accepted_group; 163 1.1 christos }; 164 1.1 christos 165 1.1 christos 166 1.1 christos 167 1.1 christos /* output port ID's */ 168 1.1 christos 169 1.1 christos enum { 170 1.1 christos NMI_PORT, 171 1.1 christos LEVEL_PORT, 172 1.1 christos }; 173 1.1 christos 174 1.1 christos 175 1.1 christos /* input port ID's */ 176 1.1 christos 177 1.1 christos enum { 178 1.1 christos G0_PORT = 0, 179 1.1 christos G1_PORT = 4, 180 1.1 christos G2_PORT = 8, 181 1.1 christos G3_PORT = 12, 182 1.1 christos G4_PORT = 16, 183 1.1 christos G5_PORT = 20, 184 1.1 christos G6_PORT = 24, 185 1.1 christos G7_PORT = 28, 186 1.1 christos G8_PORT = 32, 187 1.1 christos G9_PORT = 36, 188 1.1 christos G10_PORT = 40, 189 1.1 christos G11_PORT = 44, 190 1.1 christos G12_PORT = 48, 191 1.1 christos G13_PORT = 52, 192 1.1 christos G14_PORT = 56, 193 1.1 christos G15_PORT = 60, 194 1.1 christos G16_PORT = 64, 195 1.1 christos G17_PORT = 68, 196 1.1 christos G18_PORT = 72, 197 1.1 christos G19_PORT = 76, 198 1.1 christos G20_PORT = 80, 199 1.1 christos G21_PORT = 84, 200 1.1 christos G22_PORT = 88, 201 1.1 christos G23_PORT = 92, 202 1.1 christos IRQ0_PORT = G23_PORT, 203 1.1 christos G24_PORT = 96, 204 1.1 christos G25_PORT = 100, 205 1.1 christos G26_PORT = 104, 206 1.1 christos G27_PORT = 108, 207 1.1 christos IRQ4_PORT = G27_PORT, 208 1.1 christos G28_PORT = 112, 209 1.1 christos G29_PORT = 116, 210 1.1 christos G30_PORT = 120, 211 1.1 christos NR_G_PORTS = 124, 212 1.1 christos ACK_PORT, 213 1.1 christos }; 214 1.1 christos 215 1.1 christos static const struct hw_port_descriptor mn103int_ports[] = { 216 1.1 christos 217 1.1 christos /* interrupt outputs */ 218 1.1 christos 219 1.1 christos { "nmi", NMI_PORT, 0, output_port, }, 220 1.1 christos { "level", LEVEL_PORT, 0, output_port, }, 221 1.1 christos 222 1.1 christos /* interrupt ack (latch) input from cpu */ 223 1.1 christos 224 1.1 christos { "ack", ACK_PORT, 0, input_port, }, 225 1.1 christos 226 1.1 christos /* interrupt inputs (as names) */ 227 1.1 christos 228 1.1 christos { "nmirq", G0_PORT + 0, 0, input_port, }, 229 1.1 christos { "watchdog", G0_PORT + 1, 0, input_port, }, 230 1.1 christos { "syserr", G0_PORT + 2, 0, input_port, }, 231 1.1 christos 232 1.1 christos { "timer-0-underflow", G2_PORT, 0, input_port, }, 233 1.1 christos { "timer-1-underflow", G3_PORT, 0, input_port, }, 234 1.1 christos { "timer-2-underflow", G4_PORT, 0, input_port, }, 235 1.1 christos { "timer-3-underflow", G5_PORT, 0, input_port, }, 236 1.1 christos { "timer-4-underflow", G6_PORT, 0, input_port, }, 237 1.1 christos { "timer-5-underflow", G7_PORT, 0, input_port, }, 238 1.1 christos { "timer-6-underflow", G8_PORT, 0, input_port, }, 239 1.1 christos 240 1.1 christos { "timer-6-compare-a", G9_PORT, 0, input_port, }, 241 1.1 christos { "timer-6-compare-b", G10_PORT, 0, input_port, }, 242 1.1 christos 243 1.1 christos { "dma-0-end", G12_PORT, 0, input_port, }, 244 1.1 christos { "dma-1-end", G13_PORT, 0, input_port, }, 245 1.1 christos { "dma-2-end", G14_PORT, 0, input_port, }, 246 1.1 christos { "dma-3-end", G15_PORT, 0, input_port, }, 247 1.1 christos 248 1.1 christos { "serial-0-receive", G16_PORT, 0, input_port, }, 249 1.1 christos { "serial-0-transmit", G17_PORT, 0, input_port, }, 250 1.1 christos 251 1.1 christos { "serial-1-receive", G18_PORT, 0, input_port, }, 252 1.1 christos { "serial-1-transmit", G19_PORT, 0, input_port, }, 253 1.1 christos 254 1.1 christos { "serial-2-receive", G20_PORT, 0, input_port, }, 255 1.1 christos { "serial-2-transmit", G21_PORT, 0, input_port, }, 256 1.1 christos 257 1.1 christos { "irq-0", G23_PORT, 0, input_port, }, 258 1.1 christos { "irq-1", G24_PORT, 0, input_port, }, 259 1.1 christos { "irq-2", G25_PORT, 0, input_port, }, 260 1.1 christos { "irq-3", G26_PORT, 0, input_port, }, 261 1.1 christos { "irq-4", G27_PORT, 0, input_port, }, 262 1.1 christos { "irq-5", G28_PORT, 0, input_port, }, 263 1.1 christos { "irq-6", G29_PORT, 0, input_port, }, 264 1.1 christos { "irq-7", G30_PORT, 0, input_port, }, 265 1.1 christos 266 1.1 christos /* interrupt inputs (as generic numbers) */ 267 1.1 christos 268 1.1 christos { "int", 0, NR_G_PORTS, input_port, }, 269 1.1 christos 270 1.1 christos { NULL, }, 271 1.1 christos }; 272 1.1 christos 273 1.1 christos 274 1.1 christos /* Macros for extracting/restoring the various register bits */ 275 1.1 christos 276 1.1 christos #define EXTRACT_ID(X) (LSEXTRACTED8 ((X), 3, 0)) 277 1.1 christos #define INSERT_ID(X) (LSINSERTED8 ((X), 3, 0)) 278 1.1 christos 279 1.1 christos #define EXTRACT_IR(X) (LSEXTRACTED8 ((X), 7, 4)) 280 1.1 christos #define INSERT_IR(X) (LSINSERTED8 ((X), 7, 4)) 281 1.1 christos 282 1.1 christos #define EXTRACT_IE(X) (LSEXTRACTED8 ((X), 3, 0)) 283 1.1 christos #define INSERT_IE(X) (LSINSERTED8 ((X), 3, 0)) 284 1.1 christos 285 1.1 christos #define EXTRACT_LV(X) (LSEXTRACTED8 ((X), 6, 4)) 286 1.1 christos #define INSERT_LV(X) (LSINSERTED8 ((X), 6, 4)) 287 1.1 christos 288 1.1 christos 289 1.1 christos 290 1.1 christos /* Finish off the partially created hw device. Attach our local 291 1.1 christos callbacks. Wire up our port names etc */ 292 1.1 christos 293 1.1 christos static hw_io_read_buffer_method mn103int_io_read_buffer; 294 1.1 christos static hw_io_write_buffer_method mn103int_io_write_buffer; 295 1.1 christos static hw_port_event_method mn103int_port_event; 296 1.1 christos static hw_ioctl_method mn103int_ioctl; 297 1.1 christos 298 1.1 christos 299 1.1 christos 300 1.1 christos static void 301 1.1 christos attach_mn103int_regs (struct hw *me, 302 1.1 christos struct mn103int *controller) 303 1.1 christos { 304 1.1 christos int i; 305 1.1 christos if (hw_find_property (me, "reg") == NULL) 306 1.1 christos hw_abort (me, "Missing \"reg\" property"); 307 1.1 christos for (i = 0; i < NR_BLOCKS; i++) 308 1.1 christos { 309 1.1 christos unsigned_word attach_address; 310 1.1 christos int attach_space; 311 1.1 christos unsigned attach_size; 312 1.1 christos reg_property_spec reg; 313 1.1 christos if (!hw_find_reg_array_property (me, "reg", i, ®)) 314 1.1 christos hw_abort (me, "\"reg\" property must contain three addr/size entries"); 315 1.1 christos hw_unit_address_to_attach_address (hw_parent (me), 316 1.1 christos ®.address, 317 1.1 christos &attach_space, 318 1.1 christos &attach_address, 319 1.1 christos me); 320 1.1 christos controller->block[i].base = attach_address; 321 1.1 christos hw_unit_size_to_attach_size (hw_parent (me), 322 1.1 christos ®.size, 323 1.1 christos &attach_size, me); 324 1.1 christos controller->block[i].bound = attach_address + (attach_size - 1); 325 1.1 christos hw_attach_address (hw_parent (me), 326 1.1 christos 0, 327 1.1 christos attach_space, attach_address, attach_size, 328 1.1 christos me); 329 1.1 christos } 330 1.1 christos } 331 1.1 christos 332 1.1 christos static void 333 1.1 christos mn103int_finish (struct hw *me) 334 1.1 christos { 335 1.1 christos int gid; 336 1.1 christos struct mn103int *controller; 337 1.1 christos 338 1.1 christos controller = HW_ZALLOC (me, struct mn103int); 339 1.1 christos set_hw_data (me, controller); 340 1.1 christos set_hw_io_read_buffer (me, mn103int_io_read_buffer); 341 1.1 christos set_hw_io_write_buffer (me, mn103int_io_write_buffer); 342 1.1 christos set_hw_ports (me, mn103int_ports); 343 1.1 christos set_hw_port_event (me, mn103int_port_event); 344 1.1 christos me->to_ioctl = mn103int_ioctl; 345 1.1 christos 346 1.1 christos /* Attach ourself to our parent bus */ 347 1.1 christos attach_mn103int_regs (me, controller); 348 1.1 christos 349 1.1 christos /* Initialize all the groups according to their default configuration */ 350 1.1 christos for (gid = 0; gid < NR_GROUPS; gid++) 351 1.1 christos { 352 1.1 christos struct mn103int_group *group = &controller->group[gid]; 353 1.1 christos group->trigger = NEGATIVE_EDGE; 354 1.1 christos group->gid = gid; 355 1.1 christos if (FIRST_NMI_GROUP <= gid && gid <= LAST_NMI_GROUP) 356 1.1 christos { 357 1.1 christos group->enable = 0xf; 358 1.1 christos group->type = NMI_GROUP; 359 1.1 christos } 360 1.1 christos else if (FIRST_LEVEL_GROUP <= gid && gid <= LAST_LEVEL_GROUP) 361 1.1 christos { 362 1.1 christos group->enable = 0x0; 363 1.1 christos group->type = LEVEL_GROUP; 364 1.1 christos } 365 1.1 christos else 366 1.1 christos hw_abort (me, "internal error - unknown group id"); 367 1.1 christos } 368 1.1 christos } 369 1.1 christos 370 1.1 christos 371 1.1 christos 372 1.1 christos /* Perform the nasty work of figuring out which of the interrupt 373 1.1 christos groups should have its interrupt delivered. */ 374 1.1 christos 375 1.1 christos static int 376 1.1 christos find_highest_interrupt_group (struct hw *me, 377 1.1 christos struct mn103int *controller) 378 1.1 christos { 379 1.1 christos int gid; 380 1.1 christos int selected; 381 1.1 christos 382 1.1 christos /* FIRST_NMI_GROUP (group zero) is used as a special default value 383 1.1 christos when searching for an interrupt group.*/ 384 1.1 christos selected = FIRST_NMI_GROUP; 385 1.1 christos controller->group[FIRST_NMI_GROUP].level = 7; 386 1.1 christos 387 1.1 christos for (gid = FIRST_LEVEL_GROUP; gid <= LAST_LEVEL_GROUP; gid++) 388 1.1 christos { 389 1.1 christos struct mn103int_group *group = &controller->group[gid]; 390 1.1 christos if ((group->request & group->enable) != 0) 391 1.1 christos { 392 1.1 christos /* Remember, lower level, higher priority. */ 393 1.1 christos if (group->level < controller->group[selected].level) 394 1.1 christos { 395 1.1 christos selected = gid; 396 1.1 christos } 397 1.1 christos } 398 1.1 christos } 399 1.1 christos return selected; 400 1.1 christos } 401 1.1 christos 402 1.1 christos 403 1.1 christos /* Notify the processor of an interrupt level update */ 404 1.1 christos 405 1.1 christos static void 406 1.1 christos push_interrupt_level (struct hw *me, 407 1.1 christos struct mn103int *controller) 408 1.1 christos { 409 1.1 christos int selected = find_highest_interrupt_group (me, controller); 410 1.1 christos int level = controller->group[selected].level; 411 1.1 christos HW_TRACE ((me, "port-out - selected=%d level=%d", selected, level)); 412 1.1 christos hw_port_event (me, LEVEL_PORT, level); 413 1.1 christos } 414 1.1 christos 415 1.1 christos 416 1.1 christos /* An event arrives on an interrupt port */ 417 1.1 christos 418 1.1 christos static void 419 1.1 christos mn103int_port_event (struct hw *me, 420 1.1 christos int my_port, 421 1.1 christos struct hw *source, 422 1.1 christos int source_port, 423 1.1 christos int level) 424 1.1 christos { 425 1.1 christos struct mn103int *controller = hw_data (me); 426 1.1 christos 427 1.1 christos switch (my_port) 428 1.1 christos { 429 1.1 christos 430 1.1 christos case ACK_PORT: 431 1.1 christos { 432 1.1 christos int selected = find_highest_interrupt_group (me, controller); 433 1.1 christos if (controller->group[selected].level != level) 434 1.1 christos hw_abort (me, "botched level synchronisation"); 435 1.1 christos controller->interrupt_accepted_group = selected; 436 1.1 christos HW_TRACE ((me, "port-event port=ack level=%d - selected=%d", 437 1.1 christos level, selected)); 438 1.1 christos break; 439 1.1 christos } 440 1.1 christos 441 1.1 christos default: 442 1.1 christos { 443 1.1 christos int gid; 444 1.1 christos int iid; 445 1.1 christos struct mn103int_group *group; 446 1.1 christos unsigned interrupt; 447 1.1 christos if (my_port > NR_G_PORTS) 448 1.1 christos hw_abort (me, "Event on unknown port %d", my_port); 449 1.1 christos 450 1.1 christos /* map the port onto an interrupt group */ 451 1.1 christos gid = (my_port % NR_G_PORTS) / 4; 452 1.1 christos group = &controller->group[gid]; 453 1.1 christos iid = (my_port % 4); 454 1.1 christos interrupt = 1 << iid; 455 1.1 christos 456 1.1 christos /* update our cached input */ 457 1.1 christos if (level) 458 1.1 christos group->input |= interrupt; 459 1.1 christos else 460 1.1 christos group->input &= ~interrupt; 461 1.1 christos 462 1.1 christos /* update the request bits */ 463 1.1 christos switch (group->trigger) 464 1.1 christos { 465 1.1 christos case ACTIVE_LOW: 466 1.1 christos case ACTIVE_HIGH: 467 1.1 christos if (level) 468 1.1 christos group->request |= interrupt; 469 1.1 christos break; 470 1.1 christos case NEGATIVE_EDGE: 471 1.1 christos case POSITIVE_EDGE: 472 1.1 christos group->request |= interrupt; 473 1.1 christos } 474 1.1 christos 475 1.1 christos /* force a corresponding output */ 476 1.1 christos switch (group->type) 477 1.1 christos { 478 1.1 christos 479 1.1 christos case NMI_GROUP: 480 1.1 christos { 481 1.1 christos /* for NMI's the event is the trigger */ 482 1.1 christos HW_TRACE ((me, "port-in port=%d group=%d interrupt=%d - NMI", 483 1.1 christos my_port, gid, iid)); 484 1.1 christos if ((group->request & group->enable) != 0) 485 1.1 christos { 486 1.1 christos HW_TRACE ((me, "port-out NMI")); 487 1.1 christos hw_port_event (me, NMI_PORT, 1); 488 1.1 christos } 489 1.1 christos break; 490 1.1 christos } 491 1.1 christos 492 1.1 christos case LEVEL_GROUP: 493 1.1 christos { 494 1.1 christos /* if an interrupt is now pending */ 495 1.1 christos HW_TRACE ((me, "port-in port=%d group=%d interrupt=%d - INT", 496 1.1 christos my_port, gid, iid)); 497 1.1 christos push_interrupt_level (me, controller); 498 1.1 christos break; 499 1.1 christos } 500 1.1 christos } 501 1.1 christos break; 502 1.1 christos } 503 1.1 christos 504 1.1 christos } 505 1.1 christos } 506 1.1 christos 507 1.1 christos /* Read/write to to an ICR (group control register) */ 508 1.1 christos 509 1.1 christos static struct mn103int_group * 510 1.1 christos decode_group (struct hw *me, 511 1.1 christos struct mn103int *controller, 512 1.1 christos unsigned_word base, 513 1.1 christos unsigned_word *offset) 514 1.1 christos { 515 1.1 christos int gid = (base / 4) % NR_GROUPS; 516 1.1 christos *offset = (base % 4); 517 1.1 christos return &controller->group[gid]; 518 1.1 christos } 519 1.1 christos 520 1.10 christos static uint8_t 521 1.1 christos read_icr (struct hw *me, 522 1.1 christos struct mn103int *controller, 523 1.1 christos unsigned_word base) 524 1.1 christos { 525 1.1 christos unsigned_word offset; 526 1.1 christos struct mn103int_group *group = decode_group (me, controller, base, &offset); 527 1.10 christos uint8_t val = 0; 528 1.1 christos switch (group->type) 529 1.1 christos { 530 1.1 christos 531 1.1 christos case NMI_GROUP: 532 1.1 christos switch (offset) 533 1.1 christos { 534 1.1 christos case 0: 535 1.1 christos val = INSERT_ID (group->request); 536 1.1 christos HW_TRACE ((me, "read-icr group=%d:0 nmi 0x%02x", 537 1.1 christos group->gid, val)); 538 1.1 christos break; 539 1.1 christos default: 540 1.1 christos break; 541 1.1 christos } 542 1.1 christos break; 543 1.1 christos 544 1.1 christos case LEVEL_GROUP: 545 1.1 christos switch (offset) 546 1.1 christos { 547 1.1 christos case 0: 548 1.1 christos val = (INSERT_IR (group->request) 549 1.1 christos | INSERT_ID (group->request & group->enable)); 550 1.1 christos HW_TRACE ((me, "read-icr group=%d:0 level 0x%02x", 551 1.1 christos group->gid, val)); 552 1.1 christos break; 553 1.1 christos case 1: 554 1.1 christos val = (INSERT_LV (group->level) 555 1.1 christos | INSERT_IE (group->enable)); 556 1.1 christos HW_TRACE ((me, "read-icr level-%d:1 level 0x%02x", 557 1.1 christos group->gid, val)); 558 1.1 christos break; 559 1.1 christos } 560 1.1 christos break; 561 1.1 christos 562 1.1 christos default: 563 1.1 christos break; 564 1.1 christos 565 1.1 christos } 566 1.1 christos 567 1.1 christos return val; 568 1.1 christos } 569 1.1 christos 570 1.1 christos static void 571 1.1 christos write_icr (struct hw *me, 572 1.1 christos struct mn103int *controller, 573 1.1 christos unsigned_word base, 574 1.10 christos uint8_t val) 575 1.1 christos { 576 1.1 christos unsigned_word offset; 577 1.1 christos struct mn103int_group *group = decode_group (me, controller, base, &offset); 578 1.1 christos switch (group->type) 579 1.1 christos { 580 1.1 christos 581 1.1 christos case NMI_GROUP: 582 1.1 christos switch (offset) 583 1.1 christos { 584 1.1 christos case 0: 585 1.1 christos HW_TRACE ((me, "write-icr group=%d:0 nmi 0x%02x", 586 1.1 christos group->gid, val)); 587 1.1 christos group->request &= ~EXTRACT_ID (val); 588 1.1 christos break; 589 1.1 christos /* Special backdoor access to SYSEF flag from CPU. See 590 1.1 christos interp.c:program_interrupt(). */ 591 1.1 christos case 3: 592 1.1 christos HW_TRACE ((me, "write-icr-special group=%d:0 nmi 0x%02x", 593 1.1 christos group->gid, val)); 594 1.1 christos group->request |= EXTRACT_ID (val); 595 1.1 christos default: 596 1.1 christos break; 597 1.1 christos } 598 1.1 christos break; 599 1.1 christos 600 1.1 christos case LEVEL_GROUP: 601 1.1 christos switch (offset) 602 1.1 christos { 603 1.1 christos case 0: /* request/detect */ 604 1.1 christos /* Clear any ID bits and then set them according to IR */ 605 1.1 christos HW_TRACE ((me, "write-icr group=%d:0 level 0x%02x %x:%x:%x", 606 1.1 christos group->gid, val, 607 1.1 christos group->request, EXTRACT_IR (val), EXTRACT_ID (val))); 608 1.1 christos group->request = 609 1.1 christos ((EXTRACT_IR (val) & EXTRACT_ID (val)) 610 1.1 christos | (EXTRACT_IR (val) & group->request) 611 1.1 christos | (~EXTRACT_IR (val) & ~EXTRACT_ID (val) & group->request)); 612 1.1 christos break; 613 1.1 christos case 1: /* level/enable */ 614 1.1 christos HW_TRACE ((me, "write-icr group=%d:1 level 0x%02x", 615 1.1 christos group->gid, val)); 616 1.1 christos group->level = EXTRACT_LV (val); 617 1.1 christos group->enable = EXTRACT_IE (val); 618 1.1 christos break; 619 1.1 christos default: 620 1.1 christos /* ignore */ 621 1.1 christos break; 622 1.1 christos } 623 1.1 christos push_interrupt_level (me, controller); 624 1.1 christos break; 625 1.1 christos 626 1.1 christos default: 627 1.1 christos break; 628 1.1 christos 629 1.1 christos } 630 1.1 christos } 631 1.1 christos 632 1.1 christos 633 1.1 christos /* Read the IAGR (Interrupt accepted group register) */ 634 1.1 christos 635 1.10 christos static uint8_t 636 1.1 christos read_iagr (struct hw *me, 637 1.1 christos struct mn103int *controller, 638 1.1 christos unsigned_word offset) 639 1.1 christos { 640 1.10 christos uint8_t val; 641 1.1 christos switch (offset) 642 1.1 christos { 643 1.1 christos case 0: 644 1.1 christos { 645 1.1 christos if (!(controller->group[controller->interrupt_accepted_group].request 646 1.1 christos & controller->group[controller->interrupt_accepted_group].enable)) 647 1.1 christos { 648 1.1 christos /* oops, lost the request */ 649 1.1 christos val = 0; 650 1.1 christos HW_TRACE ((me, "read-iagr:0 lost-0")); 651 1.1 christos } 652 1.1 christos else 653 1.1 christos { 654 1.1 christos val = (controller->interrupt_accepted_group << 2); 655 1.1 christos HW_TRACE ((me, "read-iagr:0 %d", (int) val)); 656 1.1 christos } 657 1.1 christos break; 658 1.1 christos } 659 1.1 christos case 1: 660 1.1 christos val = 0; 661 1.1 christos HW_TRACE ((me, "read-iagr:1 %d", (int) val)); 662 1.1 christos break; 663 1.1 christos default: 664 1.1 christos val = 0; 665 1.1 christos HW_TRACE ((me, "read-iagr 0x%08lx bad offset", (long) offset)); 666 1.1 christos break; 667 1.1 christos } 668 1.1 christos return val; 669 1.1 christos } 670 1.1 christos 671 1.1 christos 672 1.1 christos /* Reads/writes to the EXTMD (external interrupt trigger configuration 673 1.1 christos register) */ 674 1.1 christos 675 1.1 christos static struct mn103int_group * 676 1.1 christos external_group (struct mn103int *controller, 677 1.1 christos unsigned_word offset) 678 1.1 christos { 679 1.1 christos switch (offset) 680 1.1 christos { 681 1.1 christos case 0: 682 1.1 christos return &controller->group[IRQ0_PORT/4]; 683 1.1 christos case 1: 684 1.1 christos return &controller->group[IRQ4_PORT/4]; 685 1.1 christos default: 686 1.1 christos return NULL; 687 1.1 christos } 688 1.1 christos } 689 1.1 christos 690 1.10 christos static uint8_t 691 1.1 christos read_extmd (struct hw *me, 692 1.1 christos struct mn103int *controller, 693 1.1 christos unsigned_word offset) 694 1.1 christos { 695 1.1 christos int gid; 696 1.10 christos uint8_t val = 0; 697 1.1 christos struct mn103int_group *group = external_group (controller, offset); 698 1.1 christos if (group != NULL) 699 1.1 christos { 700 1.1 christos for (gid = 0; gid < 4; gid++) 701 1.1 christos { 702 1.1 christos val |= (group[gid].trigger << (gid * 2)); 703 1.1 christos } 704 1.1 christos } 705 1.1 christos HW_TRACE ((me, "read-extmd 0x%02lx", (long) val)); 706 1.1 christos return val; 707 1.1 christos } 708 1.1 christos 709 1.1 christos static void 710 1.1 christos write_extmd (struct hw *me, 711 1.1 christos struct mn103int *controller, 712 1.1 christos unsigned_word offset, 713 1.10 christos uint8_t val) 714 1.1 christos { 715 1.1 christos int gid; 716 1.1 christos struct mn103int_group *group = external_group (controller, offset); 717 1.1 christos if (group != NULL) 718 1.1 christos { 719 1.1 christos for (gid = 0; gid < 4; gid++) 720 1.1 christos { 721 1.1 christos group[gid].trigger = (val >> (gid * 2)) & 0x3; 722 1.1 christos /* MAYBE: interrupts already pending? */ 723 1.1 christos } 724 1.1 christos } 725 1.1 christos HW_TRACE ((me, "write-extmd 0x%02lx", (long) val)); 726 1.1 christos } 727 1.1 christos 728 1.1 christos 729 1.1 christos /* generic read/write */ 730 1.1 christos 731 1.1 christos static int 732 1.1 christos decode_addr (struct hw *me, 733 1.1 christos struct mn103int *controller, 734 1.1 christos unsigned_word address, 735 1.1 christos unsigned_word *offset) 736 1.1 christos { 737 1.1 christos int i; 738 1.1 christos for (i = 0; i < NR_BLOCKS; i++) 739 1.1 christos { 740 1.1 christos if (address >= controller->block[i].base 741 1.1 christos && address <= controller->block[i].bound) 742 1.1 christos { 743 1.1 christos *offset = address - controller->block[i].base; 744 1.1 christos return i; 745 1.1 christos } 746 1.1 christos } 747 1.1 christos hw_abort (me, "bad address"); 748 1.1 christos return -1; 749 1.1 christos } 750 1.1 christos 751 1.1 christos static unsigned 752 1.1 christos mn103int_io_read_buffer (struct hw *me, 753 1.1 christos void *dest, 754 1.1 christos int space, 755 1.1 christos unsigned_word base, 756 1.1 christos unsigned nr_bytes) 757 1.1 christos { 758 1.1 christos struct mn103int *controller = hw_data (me); 759 1.10 christos uint8_t *buf = dest; 760 1.1 christos unsigned byte; 761 1.1 christos /* HW_TRACE ((me, "read 0x%08lx %d", (long) base, (int) nr_bytes)); */ 762 1.1 christos for (byte = 0; byte < nr_bytes; byte++) 763 1.1 christos { 764 1.1 christos unsigned_word address = base + byte; 765 1.1 christos unsigned_word offset; 766 1.1 christos switch (decode_addr (me, controller, address, &offset)) 767 1.1 christos { 768 1.1 christos case ICR_BLOCK: 769 1.1 christos buf[byte] = read_icr (me, controller, offset); 770 1.1 christos break; 771 1.1 christos case IAGR_BLOCK: 772 1.1 christos buf[byte] = read_iagr (me, controller, offset); 773 1.1 christos break; 774 1.1 christos case EXTMD_BLOCK: 775 1.1 christos buf[byte] = read_extmd (me, controller, offset); 776 1.1 christos break; 777 1.1 christos default: 778 1.1 christos hw_abort (me, "bad switch"); 779 1.1 christos } 780 1.1 christos } 781 1.1 christos return nr_bytes; 782 1.1 christos } 783 1.1 christos 784 1.1 christos static unsigned 785 1.1 christos mn103int_io_write_buffer (struct hw *me, 786 1.1 christos const void *source, 787 1.1 christos int space, 788 1.1 christos unsigned_word base, 789 1.1 christos unsigned nr_bytes) 790 1.1 christos { 791 1.1 christos struct mn103int *controller = hw_data (me); 792 1.10 christos const uint8_t *buf = source; 793 1.1 christos unsigned byte; 794 1.1 christos /* HW_TRACE ((me, "write 0x%08lx %d", (long) base, (int) nr_bytes)); */ 795 1.1 christos for (byte = 0; byte < nr_bytes; byte++) 796 1.1 christos { 797 1.1 christos unsigned_word address = base + byte; 798 1.1 christos unsigned_word offset; 799 1.1 christos switch (decode_addr (me, controller, address, &offset)) 800 1.1 christos { 801 1.1 christos case ICR_BLOCK: 802 1.1 christos write_icr (me, controller, offset, buf[byte]); 803 1.1 christos break; 804 1.1 christos case IAGR_BLOCK: 805 1.1 christos /* not allowed */ 806 1.1 christos break; 807 1.1 christos case EXTMD_BLOCK: 808 1.1 christos write_extmd (me, controller, offset, buf[byte]); 809 1.1 christos break; 810 1.1 christos default: 811 1.1 christos hw_abort (me, "bad switch"); 812 1.1 christos } 813 1.1 christos } 814 1.1 christos return nr_bytes; 815 1.1 christos } 816 1.1 christos 817 1.1 christos static int 818 1.1 christos mn103int_ioctl(struct hw *me, 819 1.1 christos hw_ioctl_request request, 820 1.1 christos va_list ap) 821 1.1 christos { 822 1.1 christos struct mn103int *controller = (struct mn103int *)hw_data(me); 823 1.1 christos controller->group[0].request = EXTRACT_ID(4); 824 1.1 christos mn103int_port_event(me, 2 /* nmi_port(syserr) */, NULL, 0, 0); 825 1.1 christos return 0; 826 1.1 christos } 827 1.1 christos 828 1.1 christos 829 1.1 christos const struct hw_descriptor dv_mn103int_descriptor[] = { 830 1.1 christos { "mn103int", mn103int_finish, }, 831 1.1 christos { NULL }, 832 1.1 christos }; 833