1 /* 2 * ColdFire Interrupt Controller emulation. 3 * 4 * Copyright (c) 2007 CodeSourcery. 5 * 6 * This code is licensed under the GPL 7 */ 8 9 #include "qemu/osdep.h" 10 #include "qapi/error.h" 11 #include "qemu/module.h" 12 #include "qemu/log.h" 13 #include "cpu.h" 14 #include "hw/hw.h" 15 #include "hw/irq.h" 16 #include "hw/sysbus.h" 17 #include "hw/m68k/mcf.h" 18 #include "qom/object.h" 19 20 #define TYPE_MCF_INTC "mcf-intc" 21 typedef struct mcf_intc_state mcf_intc_state; 22 #define MCF_INTC(obj) OBJECT_CHECK(mcf_intc_state, (obj), TYPE_MCF_INTC) 23 24 struct mcf_intc_state { 25 SysBusDevice parent_obj; 26 27 MemoryRegion iomem; 28 uint64_t ipr; 29 uint64_t imr; 30 uint64_t ifr; 31 uint64_t enabled; 32 uint8_t icr[64]; 33 M68kCPU *cpu; 34 int active_vector; 35 }; 36 37 static void mcf_intc_update(mcf_intc_state *s) 38 { 39 uint64_t active; 40 int i; 41 int best; 42 int best_level; 43 44 active = (s->ipr | s->ifr) & s->enabled & ~s->imr; 45 best_level = 0; 46 best = 64; 47 if (active) { 48 for (i = 0; i < 64; i++) { 49 if ((active & 1) != 0 && s->icr[i] >= best_level) { 50 best_level = s->icr[i]; 51 best = i; 52 } 53 active >>= 1; 54 } 55 } 56 s->active_vector = ((best == 64) ? 24 : (best + 64)); 57 m68k_set_irq_level(s->cpu, best_level, s->active_vector); 58 } 59 60 static uint64_t mcf_intc_read(void *opaque, hwaddr addr, 61 unsigned size) 62 { 63 int offset; 64 mcf_intc_state *s = (mcf_intc_state *)opaque; 65 offset = addr & 0xff; 66 if (offset >= 0x40 && offset < 0x80) { 67 return s->icr[offset - 0x40]; 68 } 69 switch (offset) { 70 case 0x00: 71 return (uint32_t)(s->ipr >> 32); 72 case 0x04: 73 return (uint32_t)s->ipr; 74 case 0x08: 75 return (uint32_t)(s->imr >> 32); 76 case 0x0c: 77 return (uint32_t)s->imr; 78 case 0x10: 79 return (uint32_t)(s->ifr >> 32); 80 case 0x14: 81 return (uint32_t)s->ifr; 82 case 0xe0: /* SWIACK. */ 83 return s->active_vector; 84 case 0xe1: case 0xe2: case 0xe3: case 0xe4: 85 case 0xe5: case 0xe6: case 0xe7: 86 /* LnIACK */ 87 qemu_log_mask(LOG_UNIMP, "%s: LnIACK not implemented (offset 0x%02x)\n", 88 __func__, offset); 89 /* fallthru */ 90 default: 91 return 0; 92 } 93 } 94 95 static void mcf_intc_write(void *opaque, hwaddr addr, 96 uint64_t val, unsigned size) 97 { 98 int offset; 99 mcf_intc_state *s = (mcf_intc_state *)opaque; 100 offset = addr & 0xff; 101 if (offset >= 0x40 && offset < 0x80) { 102 int n = offset - 0x40; 103 s->icr[n] = val; 104 if (val == 0) 105 s->enabled &= ~(1ull << n); 106 else 107 s->enabled |= (1ull << n); 108 mcf_intc_update(s); 109 return; 110 } 111 switch (offset) { 112 case 0x00: case 0x04: 113 /* Ignore IPR writes. */ 114 return; 115 case 0x08: 116 s->imr = (s->imr & 0xffffffff) | ((uint64_t)val << 32); 117 break; 118 case 0x0c: 119 s->imr = (s->imr & 0xffffffff00000000ull) | (uint32_t)val; 120 break; 121 case 0x1c: 122 if (val & 0x40) { 123 s->imr = ~0ull; 124 } else { 125 s->imr |= (0x1ull << (val & 0x3f)); 126 } 127 break; 128 case 0x1d: 129 if (val & 0x40) { 130 s->imr = 0ull; 131 } else { 132 s->imr &= ~(0x1ull << (val & 0x3f)); 133 } 134 break; 135 default: 136 qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%02x\n", 137 __func__, offset); 138 return; 139 } 140 mcf_intc_update(s); 141 } 142 143 static void mcf_intc_set_irq(void *opaque, int irq, int level) 144 { 145 mcf_intc_state *s = (mcf_intc_state *)opaque; 146 if (irq >= 64) 147 return; 148 if (level) 149 s->ipr |= 1ull << irq; 150 else 151 s->ipr &= ~(1ull << irq); 152 mcf_intc_update(s); 153 } 154 155 static void mcf_intc_reset(DeviceState *dev) 156 { 157 mcf_intc_state *s = MCF_INTC(dev); 158 159 s->imr = ~0ull; 160 s->ipr = 0; 161 s->ifr = 0; 162 s->enabled = 0; 163 memset(s->icr, 0, 64); 164 s->active_vector = 24; 165 } 166 167 static const MemoryRegionOps mcf_intc_ops = { 168 .read = mcf_intc_read, 169 .write = mcf_intc_write, 170 .endianness = DEVICE_NATIVE_ENDIAN, 171 }; 172 173 static void mcf_intc_instance_init(Object *obj) 174 { 175 mcf_intc_state *s = MCF_INTC(obj); 176 177 memory_region_init_io(&s->iomem, obj, &mcf_intc_ops, s, "mcf", 0x100); 178 } 179 180 static void mcf_intc_class_init(ObjectClass *oc, void *data) 181 { 182 DeviceClass *dc = DEVICE_CLASS(oc); 183 184 set_bit(DEVICE_CATEGORY_MISC, dc->categories); 185 dc->reset = mcf_intc_reset; 186 } 187 188 static const TypeInfo mcf_intc_gate_info = { 189 .name = TYPE_MCF_INTC, 190 .parent = TYPE_SYS_BUS_DEVICE, 191 .instance_size = sizeof(mcf_intc_state), 192 .instance_init = mcf_intc_instance_init, 193 .class_init = mcf_intc_class_init, 194 }; 195 196 static void mcf_intc_register_types(void) 197 { 198 type_register_static(&mcf_intc_gate_info); 199 } 200 201 type_init(mcf_intc_register_types) 202 203 qemu_irq *mcf_intc_init(MemoryRegion *sysmem, 204 hwaddr base, 205 M68kCPU *cpu) 206 { 207 DeviceState *dev; 208 mcf_intc_state *s; 209 210 dev = qdev_new(TYPE_MCF_INTC); 211 sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); 212 213 s = MCF_INTC(dev); 214 s->cpu = cpu; 215 216 memory_region_add_subregion(sysmem, base, &s->iomem); 217 218 return qemu_allocate_irqs(mcf_intc_set_irq, s, 64); 219 } 220