| 1 | /* |
| 2 | * QEMU AVR CPU |
| 3 | * |
| 4 | * Copyright (c) 2019-2020 Michael Rolnik |
| 5 | * |
| 6 | * This library is free software; you can redistribute it and/or |
| 7 | * modify it under the terms of the GNU Lesser General Public |
| 8 | * License as published by the Free Software Foundation; either |
| 9 | * version 2.1 of the License, or (at your option) any later version. |
| 10 | * |
| 11 | * This library 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 GNU |
| 14 | * Lesser General Public License for more details. |
| 15 | * |
| 16 | * You should have received a copy of the GNU Lesser General Public |
| 17 | * License along with this library; if not, see |
| 18 | * <http://www.gnu.org/licenses/lgpl-2.1.html> |
| 19 | */ |
| 20 | |
| 21 | #include "qemu/osdep.h" |
| 22 | #include "qapi/error.h" |
| 23 | #include "qemu/qemu-print.h" |
| 24 | #include "exec/translation-block.h" |
| 25 | #include "system/address-spaces.h" |
| 26 | #include "cpu.h" |
| 27 | #include "disas/dis-asm.h" |
| 28 | #include "tcg/debug-assert.h" |
| 29 | #include "hw/core/qdev-properties.h" |
| 30 | #include "accel/tcg/cpu-ops.h" |
| 31 | |
| 32 | static void avr_cpu_set_pc(CPUState *cs, vaddr value) |
| 33 | { |
| 34 | AVRCPU *cpu = AVR_CPU(cs); |
| 35 | |
| 36 | cpu->env.pc_w = value / 2; /* internally PC points to words */ |
| 37 | } |
| 38 | |
| 39 | static vaddr avr_cpu_get_pc(CPUState *cs) |
| 40 | { |
| 41 | AVRCPU *cpu = AVR_CPU(cs); |
| 42 | |
| 43 | return cpu->env.pc_w * 2; |
| 44 | } |
| 45 | |
| 46 | static bool avr_cpu_has_work(CPUState *cs) |
| 47 | { |
| 48 | return cpu_test_interrupt(cs, CPU_INTERRUPT_HARD | CPU_INTERRUPT_RESET) |
| 49 | && cpu_interrupts_enabled(cpu_env(cs)); |
| 50 | } |
| 51 | |
| 52 | static int avr_cpu_mmu_index(CPUState *cs, bool ifetch) |
| 53 | { |
| 54 | return ifetch ? MMU_CODE_IDX : MMU_DATA_IDX; |
| 55 | } |
| 56 | |
| 57 | static TCGTBCPUState avr_get_tb_cpu_state(CPUState *cs) |
| 58 | { |
| 59 | CPUAVRState *env = cpu_env(cs); |
| 60 | uint32_t flags = 0; |
| 61 | |
| 62 | if (env->fullacc) { |
| 63 | flags |= TB_FLAGS_FULL_ACCESS; |
| 64 | } |
| 65 | if (env->skip) { |
| 66 | flags |= TB_FLAGS_SKIP; |
| 67 | } |
| 68 | |
| 69 | return (TCGTBCPUState){ .pc = env->pc_w * 2, .flags = flags }; |
| 70 | } |
| 71 | |
| 72 | static void avr_cpu_synchronize_from_tb(CPUState *cs, |
| 73 | const TranslationBlock *tb) |
| 74 | { |
| 75 | tcg_debug_assert(!tcg_cflags_has(cs, CF_PCREL)); |
| 76 | cpu_env(cs)->pc_w = tb->pc / 2; /* internally PC points to words */ |
| 77 | } |
| 78 | |
| 79 | static void avr_restore_state_to_opc(CPUState *cs, |
| 80 | const TranslationBlock *tb, |
| 81 | const uint64_t *data) |
| 82 | { |
| 83 | cpu_env(cs)->pc_w = data[0]; |
| 84 | } |
| 85 | |
| 86 | static void avr_cpu_reset_hold(Object *obj, ResetType type) |
| 87 | { |
| 88 | CPUState *cs = CPU(obj); |
| 89 | AVRCPU *cpu = AVR_CPU(cs); |
| 90 | AVRCPUClass *mcc = AVR_CPU_GET_CLASS(obj); |
| 91 | CPUAVRState *env = &cpu->env; |
| 92 | |
| 93 | if (mcc->parent_phases.hold) { |
| 94 | mcc->parent_phases.hold(obj, type); |
| 95 | } |
| 96 | |
| 97 | env->pc_w = 0; |
| 98 | env->sregI = 1; |
| 99 | env->sregC = 0; |
| 100 | env->sregZ = 0; |
| 101 | env->sregN = 0; |
| 102 | env->sregV = 0; |
| 103 | env->sregS = 0; |
| 104 | env->sregH = 0; |
| 105 | env->sregT = 0; |
| 106 | |
| 107 | env->rampD = 0; |
| 108 | env->rampX = 0; |
| 109 | env->rampY = 0; |
| 110 | env->rampZ = 0; |
| 111 | env->eind = 0; |
| 112 | env->sp = cpu->init_sp; |
| 113 | |
| 114 | env->skip = 0; |
| 115 | |
| 116 | memset(env->r, 0, sizeof(env->r)); |
| 117 | } |
| 118 | |
| 119 | static void avr_cpu_disas_set_info(const CPUState *cpu, disassemble_info *info) |
| 120 | { |
| 121 | info->endian = BFD_ENDIAN_LITTLE; |
| 122 | info->mach = bfd_arch_avr; |
| 123 | info->print_insn = avr_print_insn; |
| 124 | } |
| 125 | |
| 126 | static void avr_cpu_realizefn(DeviceState *dev, Error **errp) |
| 127 | { |
| 128 | CPUState *cs = CPU(dev); |
| 129 | CPUAVRState *env = cpu_env(cs); |
| 130 | AVRCPU *cpu = env_archcpu(env); |
| 131 | AVRCPUClass *mcc = AVR_CPU_GET_CLASS(dev); |
| 132 | Error *local_err = NULL; |
| 133 | |
| 134 | cpu_common_realize(cs, &local_err); |
| 135 | if (local_err != NULL) { |
| 136 | error_propagate(errp, local_err); |
| 137 | return; |
| 138 | } |
| 139 | qemu_init_vcpu(cs); |
| 140 | cpu_reset(cs); |
| 141 | |
| 142 | mcc->parent_realize(dev, errp); |
| 143 | |
| 144 | /* |
| 145 | * Two blocks in the low data space loop back into cpu registers. |
| 146 | */ |
| 147 | memory_region_init_io(&cpu->cpu_reg1, OBJECT(cpu), &avr_cpu_reg1, env, |
| 148 | "avr-cpu-reg1", 32); |
| 149 | memory_region_add_subregion(get_system_memory(), |
| 150 | OFFSET_DATA, &cpu->cpu_reg1); |
| 151 | |
| 152 | memory_region_init_io(&cpu->cpu_reg2, OBJECT(cpu), &avr_cpu_reg2, env, |
| 153 | "avr-cpu-reg2", 8); |
| 154 | memory_region_add_subregion(get_system_memory(), |
| 155 | OFFSET_DATA + 0x58, &cpu->cpu_reg2); |
| 156 | } |
| 157 | |
| 158 | static void avr_cpu_set_int(void *opaque, int irq, int level) |
| 159 | { |
| 160 | AVRCPU *cpu = opaque; |
| 161 | CPUAVRState *env = &cpu->env; |
| 162 | CPUState *cs = CPU(cpu); |
| 163 | uint64_t mask = (1ull << irq); |
| 164 | |
| 165 | if (level) { |
| 166 | env->intsrc |= mask; |
| 167 | cpu_interrupt(cs, CPU_INTERRUPT_HARD); |
| 168 | } else { |
| 169 | env->intsrc &= ~mask; |
| 170 | if (env->intsrc == 0) { |
| 171 | cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); |
| 172 | } |
| 173 | } |
| 174 | } |
| 175 | |
| 176 | static void avr_cpu_initfn(Object *obj) |
| 177 | { |
| 178 | AVRCPU *cpu = AVR_CPU(obj); |
| 179 | |
| 180 | /* Set the number of interrupts supported by the CPU. */ |
| 181 | qdev_init_gpio_in(DEVICE(cpu), avr_cpu_set_int, |
| 182 | sizeof(cpu->env.intsrc) * 8); |
| 183 | } |
| 184 | |
| 185 | static const Property avr_cpu_properties[] = { |
| 186 | DEFINE_PROP_UINT32("init-sp", AVRCPU, init_sp, 0), |
| 187 | }; |
| 188 | |
| 189 | static ObjectClass *avr_cpu_class_by_name(const char *cpu_model) |
| 190 | { |
| 191 | return object_class_by_name(cpu_model); |
| 192 | } |
| 193 | |
| 194 | static void avr_cpu_dump_state(CPUState *cs, FILE *f, int flags) |
| 195 | { |
| 196 | CPUAVRState *env = cpu_env(cs); |
| 197 | int i; |
| 198 | |
| 199 | qemu_fprintf(f, "\n"); |
| 200 | qemu_fprintf(f, "PC: %06x\n", env->pc_w * 2); /* PC points to words */ |
| 201 | qemu_fprintf(f, "SP: %04x\n", env->sp); |
| 202 | qemu_fprintf(f, "rampD: %02x\n", env->rampD >> 16); |
| 203 | qemu_fprintf(f, "rampX: %02x\n", env->rampX >> 16); |
| 204 | qemu_fprintf(f, "rampY: %02x\n", env->rampY >> 16); |
| 205 | qemu_fprintf(f, "rampZ: %02x\n", env->rampZ >> 16); |
| 206 | qemu_fprintf(f, "EIND: %02x\n", env->eind >> 16); |
| 207 | qemu_fprintf(f, "X: %02x%02x\n", env->r[27], env->r[26]); |
| 208 | qemu_fprintf(f, "Y: %02x%02x\n", env->r[29], env->r[28]); |
| 209 | qemu_fprintf(f, "Z: %02x%02x\n", env->r[31], env->r[30]); |
| 210 | qemu_fprintf(f, "SREG: [ %c %c %c %c %c %c %c %c ]\n", |
| 211 | env->sregI ? 'I' : '-', |
| 212 | env->sregT ? 'T' : '-', |
| 213 | env->sregH ? 'H' : '-', |
| 214 | env->sregS ? 'S' : '-', |
| 215 | env->sregV ? 'V' : '-', |
| 216 | env->sregN ? '-' : 'N', /* Zf has negative logic */ |
| 217 | env->sregZ ? 'Z' : '-', |
| 218 | env->sregC ? 'I' : '-'); |
| 219 | qemu_fprintf(f, "SKIP: %02x\n", env->skip); |
| 220 | |
| 221 | qemu_fprintf(f, "\n"); |
| 222 | for (i = 0; i < ARRAY_SIZE(env->r); i++) { |
| 223 | qemu_fprintf(f, "R[%02d]: %02x ", i, env->r[i]); |
| 224 | |
| 225 | if ((i % 8) == 7) { |
| 226 | qemu_fprintf(f, "\n"); |
| 227 | } |
| 228 | } |
| 229 | qemu_fprintf(f, "\n"); |
| 230 | } |
| 231 | |
| 232 | #include "hw/core/sysemu-cpu-ops.h" |
| 233 | |
| 234 | static const struct SysemuCPUOps avr_sysemu_ops = { |
| 235 | .has_work = avr_cpu_has_work, |
| 236 | .get_phys_addr_debug = avr_cpu_get_phys_addr_debug, |
| 237 | }; |
| 238 | |
| 239 | static const TCGCPUOps avr_tcg_ops = { |
| 240 | .guest_default_memory_order = 0, |
| 241 | .mttcg_supported = false, |
| 242 | .initialize = avr_cpu_tcg_init, |
| 243 | .translate_code = avr_cpu_translate_code, |
| 244 | .get_tb_cpu_state = avr_get_tb_cpu_state, |
| 245 | .synchronize_from_tb = avr_cpu_synchronize_from_tb, |
| 246 | .restore_state_to_opc = avr_restore_state_to_opc, |
| 247 | .mmu_index = avr_cpu_mmu_index, |
| 248 | .cpu_exec_interrupt = avr_cpu_exec_interrupt, |
| 249 | .cpu_exec_halt = avr_cpu_has_work, |
| 250 | .cpu_exec_reset = cpu_reset, |
| 251 | .tlb_fill = avr_cpu_tlb_fill, |
| 252 | .do_interrupt = avr_cpu_do_interrupt, |
| 253 | /* |
| 254 | * TODO: code and data wrapping are different, but for the most part |
| 255 | * AVR only references bytes or aligned code fetches. But we use |
| 256 | * non-aligned MO_16 accesses for stack push/pop. |
| 257 | */ |
| 258 | .pointer_wrap = cpu_pointer_wrap_uint32, |
| 259 | }; |
| 260 | |
| 261 | static void avr_cpu_class_init(ObjectClass *oc, const void *data) |
| 262 | { |
| 263 | DeviceClass *dc = DEVICE_CLASS(oc); |
| 264 | CPUClass *cc = CPU_CLASS(oc); |
| 265 | AVRCPUClass *mcc = AVR_CPU_CLASS(oc); |
| 266 | ResettableClass *rc = RESETTABLE_CLASS(oc); |
| 267 | |
| 268 | device_class_set_parent_realize(dc, avr_cpu_realizefn, &mcc->parent_realize); |
| 269 | |
| 270 | device_class_set_props(dc, avr_cpu_properties); |
| 271 | |
| 272 | resettable_class_set_parent_phases(rc, NULL, avr_cpu_reset_hold, NULL, |
| 273 | &mcc->parent_phases); |
| 274 | |
| 275 | cc->class_by_name = avr_cpu_class_by_name; |
| 276 | |
| 277 | cc->dump_state = avr_cpu_dump_state; |
| 278 | cc->set_pc = avr_cpu_set_pc; |
| 279 | cc->get_pc = avr_cpu_get_pc; |
| 280 | dc->vmsd = &vms_avr_cpu; |
| 281 | cc->sysemu_ops = &avr_sysemu_ops; |
| 282 | cc->disas_set_info = avr_cpu_disas_set_info; |
| 283 | cc->gdb_read_register = avr_cpu_gdb_read_register; |
| 284 | cc->gdb_write_register = avr_cpu_gdb_write_register; |
| 285 | cc->gdb_adjust_breakpoint = avr_cpu_gdb_adjust_breakpoint; |
| 286 | cc->gdb_core_xml_file = "avr-cpu.xml"; |
| 287 | cc->tcg_ops = &avr_tcg_ops; |
| 288 | } |
| 289 | |
| 290 | /* |
| 291 | * Setting features of AVR core type avr5 |
| 292 | * -------------------------------------- |
| 293 | * |
| 294 | * This type of AVR core is present in the following AVR MCUs: |
| 295 | * |
| 296 | * ata5702m322, ata5782, ata5790, ata5790n, ata5791, ata5795, ata5831, ata6613c, |
| 297 | * ata6614q, ata8210, ata8510, atmega16, atmega16a, atmega161, atmega162, |
| 298 | * atmega163, atmega164a, atmega164p, atmega164pa, atmega165, atmega165a, |
| 299 | * atmega165p, atmega165pa, atmega168, atmega168a, atmega168p, atmega168pa, |
| 300 | * atmega168pb, atmega169, atmega169a, atmega169p, atmega169pa, atmega16hvb, |
| 301 | * atmega16hvbrevb, atmega16m1, atmega16u4, atmega32a, atmega32, atmega323, |
| 302 | * atmega324a, atmega324p, atmega324pa, atmega325, atmega325a, atmega325p, |
| 303 | * atmega325pa, atmega3250, atmega3250a, atmega3250p, atmega3250pa, atmega328, |
| 304 | * atmega328p, atmega328pb, atmega329, atmega329a, atmega329p, atmega329pa, |
| 305 | * atmega3290, atmega3290a, atmega3290p, atmega3290pa, atmega32c1, atmega32m1, |
| 306 | * atmega32u4, atmega32u6, atmega406, atmega64, atmega64a, atmega640, atmega644, |
| 307 | * atmega644a, atmega644p, atmega644pa, atmega645, atmega645a, atmega645p, |
| 308 | * atmega6450, atmega6450a, atmega6450p, atmega649, atmega649a, atmega649p, |
| 309 | * atmega6490, atmega16hva, atmega16hva2, atmega32hvb, atmega6490a, atmega6490p, |
| 310 | * atmega64c1, atmega64m1, atmega64hve, atmega64hve2, atmega64rfr2, |
| 311 | * atmega644rfr2, atmega32hvbrevb, at90can32, at90can64, at90pwm161, at90pwm216, |
| 312 | * at90pwm316, at90scr100, at90usb646, at90usb647, at94k, m3000 |
| 313 | */ |
| 314 | static void avr_avr5_initfn(Object *obj) |
| 315 | { |
| 316 | CPUAVRState *env = cpu_env(CPU(obj)); |
| 317 | |
| 318 | set_avr_feature(env, AVR_FEATURE_LPM); |
| 319 | set_avr_feature(env, AVR_FEATURE_IJMP_ICALL); |
| 320 | set_avr_feature(env, AVR_FEATURE_ADIW_SBIW); |
| 321 | set_avr_feature(env, AVR_FEATURE_SRAM); |
| 322 | set_avr_feature(env, AVR_FEATURE_BREAK); |
| 323 | |
| 324 | set_avr_feature(env, AVR_FEATURE_2_BYTE_PC); |
| 325 | set_avr_feature(env, AVR_FEATURE_2_BYTE_SP); |
| 326 | set_avr_feature(env, AVR_FEATURE_JMP_CALL); |
| 327 | set_avr_feature(env, AVR_FEATURE_LPMX); |
| 328 | set_avr_feature(env, AVR_FEATURE_MOVW); |
| 329 | set_avr_feature(env, AVR_FEATURE_MUL); |
| 330 | } |
| 331 | |
| 332 | /* |
| 333 | * Setting features of AVR core type avr51 |
| 334 | * -------------------------------------- |
| 335 | * |
| 336 | * This type of AVR core is present in the following AVR MCUs: |
| 337 | * |
| 338 | * atmega128, atmega128a, atmega1280, atmega1281, atmega1284, atmega1284p, |
| 339 | * atmega128rfa1, atmega128rfr2, atmega1284rfr2, at90can128, at90usb1286, |
| 340 | * at90usb1287 |
| 341 | */ |
| 342 | static void avr_avr51_initfn(Object *obj) |
| 343 | { |
| 344 | CPUAVRState *env = cpu_env(CPU(obj)); |
| 345 | |
| 346 | set_avr_feature(env, AVR_FEATURE_LPM); |
| 347 | set_avr_feature(env, AVR_FEATURE_IJMP_ICALL); |
| 348 | set_avr_feature(env, AVR_FEATURE_ADIW_SBIW); |
| 349 | set_avr_feature(env, AVR_FEATURE_SRAM); |
| 350 | set_avr_feature(env, AVR_FEATURE_BREAK); |
| 351 | |
| 352 | set_avr_feature(env, AVR_FEATURE_2_BYTE_PC); |
| 353 | set_avr_feature(env, AVR_FEATURE_2_BYTE_SP); |
| 354 | set_avr_feature(env, AVR_FEATURE_RAMPZ); |
| 355 | set_avr_feature(env, AVR_FEATURE_ELPMX); |
| 356 | set_avr_feature(env, AVR_FEATURE_ELPM); |
| 357 | set_avr_feature(env, AVR_FEATURE_JMP_CALL); |
| 358 | set_avr_feature(env, AVR_FEATURE_LPMX); |
| 359 | set_avr_feature(env, AVR_FEATURE_MOVW); |
| 360 | set_avr_feature(env, AVR_FEATURE_MUL); |
| 361 | } |
| 362 | |
| 363 | /* |
| 364 | * Setting features of AVR core type avr6 |
| 365 | * -------------------------------------- |
| 366 | * |
| 367 | * This type of AVR core is present in the following AVR MCUs: |
| 368 | * |
| 369 | * atmega2560, atmega2561, atmega256rfr2, atmega2564rfr2 |
| 370 | */ |
| 371 | static void avr_avr6_initfn(Object *obj) |
| 372 | { |
| 373 | CPUAVRState *env = cpu_env(CPU(obj)); |
| 374 | |
| 375 | set_avr_feature(env, AVR_FEATURE_LPM); |
| 376 | set_avr_feature(env, AVR_FEATURE_IJMP_ICALL); |
| 377 | set_avr_feature(env, AVR_FEATURE_ADIW_SBIW); |
| 378 | set_avr_feature(env, AVR_FEATURE_SRAM); |
| 379 | set_avr_feature(env, AVR_FEATURE_BREAK); |
| 380 | |
| 381 | set_avr_feature(env, AVR_FEATURE_3_BYTE_PC); |
| 382 | set_avr_feature(env, AVR_FEATURE_2_BYTE_SP); |
| 383 | set_avr_feature(env, AVR_FEATURE_RAMPZ); |
| 384 | set_avr_feature(env, AVR_FEATURE_EIJMP_EICALL); |
| 385 | set_avr_feature(env, AVR_FEATURE_ELPMX); |
| 386 | set_avr_feature(env, AVR_FEATURE_ELPM); |
| 387 | set_avr_feature(env, AVR_FEATURE_JMP_CALL); |
| 388 | set_avr_feature(env, AVR_FEATURE_LPMX); |
| 389 | set_avr_feature(env, AVR_FEATURE_MOVW); |
| 390 | set_avr_feature(env, AVR_FEATURE_MUL); |
| 391 | } |
| 392 | |
| 393 | typedef struct AVRCPUInfo { |
| 394 | const char *name; |
| 395 | void (*initfn)(Object *obj); |
| 396 | } AVRCPUInfo; |
| 397 | |
| 398 | |
| 399 | #define DEFINE_AVR_CPU_TYPE(model, initfn) \ |
| 400 | { \ |
| 401 | .parent = TYPE_AVR_CPU, \ |
| 402 | .instance_init = initfn, \ |
| 403 | .name = AVR_CPU_TYPE_NAME(model), \ |
| 404 | } |
| 405 | |
| 406 | static const TypeInfo avr_cpu_type_info[] = { |
| 407 | { |
| 408 | .name = TYPE_AVR_CPU, |
| 409 | .parent = TYPE_CPU, |
| 410 | .instance_size = sizeof(AVRCPU), |
| 411 | .instance_align = __alignof(AVRCPU), |
| 412 | .instance_init = avr_cpu_initfn, |
| 413 | .class_size = sizeof(AVRCPUClass), |
| 414 | .class_init = avr_cpu_class_init, |
| 415 | .abstract = true, |
| 416 | }, |
| 417 | DEFINE_AVR_CPU_TYPE("avr5", avr_avr5_initfn), |
| 418 | DEFINE_AVR_CPU_TYPE("avr51", avr_avr51_initfn), |
| 419 | DEFINE_AVR_CPU_TYPE("avr6", avr_avr6_initfn), |
| 420 | }; |
| 421 | |
| 422 | DEFINE_TYPES(avr_cpu_type_info) |