|
|
1.1 ! root 1: /* ! 2: * QEMU Sparc Sun4c interrupt controller emulation ! 3: * ! 4: * Based on slavio_intctl, copyright (c) 2003-2005 Fabrice Bellard ! 5: * ! 6: * Permission is hereby granted, free of charge, to any person obtaining a copy ! 7: * of this software and associated documentation files (the "Software"), to deal ! 8: * in the Software without restriction, including without limitation the rights ! 9: * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ! 10: * copies of the Software, and to permit persons to whom the Software is ! 11: * furnished to do so, subject to the following conditions: ! 12: * ! 13: * The above copyright notice and this permission notice shall be included in ! 14: * all copies or substantial portions of the Software. ! 15: * ! 16: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ! 17: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ! 18: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ! 19: * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ! 20: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ! 21: * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ! 22: * THE SOFTWARE. ! 23: */ ! 24: #include "hw.h" ! 25: #include "sun4m.h" ! 26: #include "console.h" ! 27: //#define DEBUG_IRQ_COUNT ! 28: //#define DEBUG_IRQ ! 29: ! 30: #ifdef DEBUG_IRQ ! 31: #define DPRINTF(fmt, args...) \ ! 32: do { printf("IRQ: " fmt , ##args); } while (0) ! 33: #else ! 34: #define DPRINTF(fmt, args...) ! 35: #endif ! 36: ! 37: /* ! 38: * Registers of interrupt controller in sun4c. ! 39: * ! 40: */ ! 41: ! 42: #define MAX_PILS 16 ! 43: ! 44: typedef struct Sun4c_INTCTLState { ! 45: #ifdef DEBUG_IRQ_COUNT ! 46: uint64_t irq_count; ! 47: #endif ! 48: qemu_irq *cpu_irqs; ! 49: const uint32_t *intbit_to_level; ! 50: uint32_t pil_out; ! 51: uint8_t reg; ! 52: uint8_t pending; ! 53: } Sun4c_INTCTLState; ! 54: ! 55: #define INTCTL_MAXADDR 0 ! 56: #define INTCTL_SIZE (INTCTL_MAXADDR + 1) ! 57: ! 58: static void sun4c_check_interrupts(void *opaque); ! 59: ! 60: static uint32_t sun4c_intctl_mem_readb(void *opaque, target_phys_addr_t addr) ! 61: { ! 62: Sun4c_INTCTLState *s = opaque; ! 63: uint32_t ret; ! 64: ! 65: ret = s->reg; ! 66: DPRINTF("read reg 0x" TARGET_FMT_plx " = %x\n", addr, ret); ! 67: ! 68: return ret; ! 69: } ! 70: ! 71: static void sun4c_intctl_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) ! 72: { ! 73: Sun4c_INTCTLState *s = opaque; ! 74: ! 75: DPRINTF("write reg 0x" TARGET_FMT_plx " = %x\n", addr, val); ! 76: val &= 0xbf; ! 77: s->reg = val; ! 78: sun4c_check_interrupts(s); ! 79: } ! 80: ! 81: static CPUReadMemoryFunc *sun4c_intctl_mem_read[3] = { ! 82: sun4c_intctl_mem_readb, ! 83: NULL, ! 84: NULL, ! 85: }; ! 86: ! 87: static CPUWriteMemoryFunc *sun4c_intctl_mem_write[3] = { ! 88: sun4c_intctl_mem_writeb, ! 89: NULL, ! 90: NULL, ! 91: }; ! 92: ! 93: void sun4c_pic_info(void *opaque) ! 94: { ! 95: Sun4c_INTCTLState *s = opaque; ! 96: ! 97: term_printf("master: pending 0x%2.2x, enabled 0x%2.2x\n", s->pending, s->reg); ! 98: } ! 99: ! 100: void sun4c_irq_info(void *opaque) ! 101: { ! 102: #ifndef DEBUG_IRQ_COUNT ! 103: term_printf("irq statistic code not compiled.\n"); ! 104: #else ! 105: Sun4c_INTCTLState *s = opaque; ! 106: int64_t count; ! 107: ! 108: term_printf("IRQ statistics:\n"); ! 109: count = s->irq_count[i]; ! 110: if (count > 0) ! 111: term_printf("%2d: %" PRId64 "\n", i, count); ! 112: #endif ! 113: } ! 114: ! 115: static const uint32_t intbit_to_level[] = { 0, 1, 4, 6, 8, 10, 0, 14, }; ! 116: ! 117: static void sun4c_check_interrupts(void *opaque) ! 118: { ! 119: Sun4c_INTCTLState *s = opaque; ! 120: uint32_t pil_pending; ! 121: unsigned int i; ! 122: ! 123: DPRINTF("pending %x disabled %x\n", pending, s->intregm_disabled); ! 124: pil_pending = 0; ! 125: if (s->pending && !(s->reg & 0x80000000)) { ! 126: for (i = 0; i < 8; i++) { ! 127: if (s->pending & (1 << i)) ! 128: pil_pending |= 1 << intbit_to_level[i]; ! 129: } ! 130: } ! 131: ! 132: for (i = 0; i < MAX_PILS; i++) { ! 133: if (pil_pending & (1 << i)) { ! 134: if (!(s->pil_out & (1 << i))) ! 135: qemu_irq_raise(s->cpu_irqs[i]); ! 136: } else { ! 137: if (s->pil_out & (1 << i)) ! 138: qemu_irq_lower(s->cpu_irqs[i]); ! 139: } ! 140: } ! 141: s->pil_out = pil_pending; ! 142: } ! 143: ! 144: /* ! 145: * "irq" here is the bit number in the system interrupt register ! 146: */ ! 147: static void sun4c_set_irq(void *opaque, int irq, int level) ! 148: { ! 149: Sun4c_INTCTLState *s = opaque; ! 150: uint32_t mask = 1 << irq; ! 151: uint32_t pil = intbit_to_level[irq]; ! 152: ! 153: DPRINTF("Set irq %d -> pil %d level %d\n", irq, pil, ! 154: level); ! 155: if (pil > 0) { ! 156: if (level) { ! 157: #ifdef DEBUG_IRQ_COUNT ! 158: s->irq_count[pil]++; ! 159: #endif ! 160: s->pending |= mask; ! 161: } else { ! 162: s->pending &= ~mask; ! 163: } ! 164: sun4c_check_interrupts(s); ! 165: } ! 166: } ! 167: ! 168: static void sun4c_intctl_save(QEMUFile *f, void *opaque) ! 169: { ! 170: Sun4c_INTCTLState *s = opaque; ! 171: ! 172: qemu_put_8s(f, &s->reg); ! 173: qemu_put_8s(f, &s->pending); ! 174: } ! 175: ! 176: static int sun4c_intctl_load(QEMUFile *f, void *opaque, int version_id) ! 177: { ! 178: Sun4c_INTCTLState *s = opaque; ! 179: ! 180: if (version_id != 1) ! 181: return -EINVAL; ! 182: ! 183: qemu_get_8s(f, &s->reg); ! 184: qemu_get_8s(f, &s->pending); ! 185: sun4c_check_interrupts(s); ! 186: ! 187: return 0; ! 188: } ! 189: ! 190: static void sun4c_intctl_reset(void *opaque) ! 191: { ! 192: Sun4c_INTCTLState *s = opaque; ! 193: ! 194: s->reg = 1; ! 195: s->pending = 0; ! 196: sun4c_check_interrupts(s); ! 197: } ! 198: ! 199: void *sun4c_intctl_init(target_phys_addr_t addr, qemu_irq **irq, ! 200: qemu_irq *parent_irq) ! 201: { ! 202: int sun4c_intctl_io_memory; ! 203: Sun4c_INTCTLState *s; ! 204: ! 205: s = qemu_mallocz(sizeof(Sun4c_INTCTLState)); ! 206: if (!s) ! 207: return NULL; ! 208: ! 209: sun4c_intctl_io_memory = cpu_register_io_memory(0, sun4c_intctl_mem_read, ! 210: sun4c_intctl_mem_write, s); ! 211: cpu_register_physical_memory(addr, INTCTL_SIZE, sun4c_intctl_io_memory); ! 212: s->cpu_irqs = parent_irq; ! 213: ! 214: register_savevm("sun4c_intctl", addr, 1, sun4c_intctl_save, ! 215: sun4c_intctl_load, s); ! 216: ! 217: qemu_register_reset(sun4c_intctl_reset, s); ! 218: *irq = qemu_allocate_irqs(sun4c_set_irq, s, 8); ! 219: ! 220: sun4c_intctl_reset(s); ! 221: return s; ! 222: } ! 223:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.