1fcf5ef2aSThomas Huth /* 2fcf5ef2aSThomas Huth * QEMU Xtensa CPU 3fcf5ef2aSThomas Huth * 4fcf5ef2aSThomas Huth * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab. 5fcf5ef2aSThomas Huth * Copyright (c) 2012 SUSE LINUX Products GmbH 6fcf5ef2aSThomas Huth * All rights reserved. 7fcf5ef2aSThomas Huth * 8fcf5ef2aSThomas Huth * Redistribution and use in source and binary forms, with or without 9fcf5ef2aSThomas Huth * modification, are permitted provided that the following conditions are met: 10fcf5ef2aSThomas Huth * * Redistributions of source code must retain the above copyright 11fcf5ef2aSThomas Huth * notice, this list of conditions and the following disclaimer. 12fcf5ef2aSThomas Huth * * Redistributions in binary form must reproduce the above copyright 13fcf5ef2aSThomas Huth * notice, this list of conditions and the following disclaimer in the 14fcf5ef2aSThomas Huth * documentation and/or other materials provided with the distribution. 15fcf5ef2aSThomas Huth * * Neither the name of the Open Source and Linux Lab nor the 16fcf5ef2aSThomas Huth * names of its contributors may be used to endorse or promote products 17fcf5ef2aSThomas Huth * derived from this software without specific prior written permission. 18fcf5ef2aSThomas Huth * 19fcf5ef2aSThomas Huth * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20fcf5ef2aSThomas Huth * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21fcf5ef2aSThomas Huth * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22fcf5ef2aSThomas Huth * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 23fcf5ef2aSThomas Huth * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24fcf5ef2aSThomas Huth * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25fcf5ef2aSThomas Huth * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 26fcf5ef2aSThomas Huth * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27fcf5ef2aSThomas Huth * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28fcf5ef2aSThomas Huth * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29fcf5ef2aSThomas Huth */ 30fcf5ef2aSThomas Huth 31fcf5ef2aSThomas Huth #include "qemu/osdep.h" 32fcf5ef2aSThomas Huth #include "qapi/error.h" 33fcf5ef2aSThomas Huth #include "cpu.h" 34cfa9f051SMax Filippov #include "fpu/softfloat.h" 350b8fa32fSMarkus Armbruster #include "qemu/module.h" 36fcf5ef2aSThomas Huth #include "migration/vmstate.h" 379e377be1SMax Filippov #include "hw/qdev-clock.h" 389585201aSPhilippe Mathieu-Daudé #ifndef CONFIG_USER_ONLY 399585201aSPhilippe Mathieu-Daudé #include "exec/memory.h" 409585201aSPhilippe Mathieu-Daudé #endif 41fcf5ef2aSThomas Huth 42fcf5ef2aSThomas Huth 43fcf5ef2aSThomas Huth static void xtensa_cpu_set_pc(CPUState *cs, vaddr value) 44fcf5ef2aSThomas Huth { 45fcf5ef2aSThomas Huth XtensaCPU *cpu = XTENSA_CPU(cs); 46fcf5ef2aSThomas Huth 47fcf5ef2aSThomas Huth cpu->env.pc = value; 48fcf5ef2aSThomas Huth } 49fcf5ef2aSThomas Huth 50e4fdf9dfSRichard Henderson static vaddr xtensa_cpu_get_pc(CPUState *cs) 51e4fdf9dfSRichard Henderson { 52e4fdf9dfSRichard Henderson XtensaCPU *cpu = XTENSA_CPU(cs); 53e4fdf9dfSRichard Henderson 54e4fdf9dfSRichard Henderson return cpu->env.pc; 55e4fdf9dfSRichard Henderson } 56e4fdf9dfSRichard Henderson 57044dcfc5SRichard Henderson static void xtensa_restore_state_to_opc(CPUState *cs, 58044dcfc5SRichard Henderson const TranslationBlock *tb, 59044dcfc5SRichard Henderson const uint64_t *data) 60044dcfc5SRichard Henderson { 61044dcfc5SRichard Henderson XtensaCPU *cpu = XTENSA_CPU(cs); 62044dcfc5SRichard Henderson 63044dcfc5SRichard Henderson cpu->env.pc = data[0]; 64044dcfc5SRichard Henderson } 65044dcfc5SRichard Henderson 66fcf5ef2aSThomas Huth static bool xtensa_cpu_has_work(CPUState *cs) 67fcf5ef2aSThomas Huth { 68ba7651fbSMax Filippov #ifndef CONFIG_USER_ONLY 69fcf5ef2aSThomas Huth XtensaCPU *cpu = XTENSA_CPU(cs); 70fcf5ef2aSThomas Huth 71bd527a83SMax Filippov return !cpu->env.runstall && cpu->env.pending_irq_level; 72ba7651fbSMax Filippov #else 73ba7651fbSMax Filippov return true; 74ba7651fbSMax Filippov #endif 75fcf5ef2aSThomas Huth } 76fcf5ef2aSThomas Huth 77130ea832SMax Filippov #ifdef CONFIG_USER_ONLY 78130ea832SMax Filippov static bool abi_call0; 79130ea832SMax Filippov 80130ea832SMax Filippov void xtensa_set_abi_call0(void) 81130ea832SMax Filippov { 82130ea832SMax Filippov abi_call0 = true; 83130ea832SMax Filippov } 84130ea832SMax Filippov 85130ea832SMax Filippov bool xtensa_abi_call0(void) 86130ea832SMax Filippov { 87130ea832SMax Filippov return abi_call0; 88130ea832SMax Filippov } 89130ea832SMax Filippov #endif 90130ea832SMax Filippov 91d66e64ddSPeter Maydell static void xtensa_cpu_reset_hold(Object *obj) 92fcf5ef2aSThomas Huth { 93d66e64ddSPeter Maydell CPUState *s = CPU(obj); 94fcf5ef2aSThomas Huth XtensaCPU *cpu = XTENSA_CPU(s); 95fcf5ef2aSThomas Huth XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cpu); 96fcf5ef2aSThomas Huth CPUXtensaState *env = &cpu->env; 97cfa9f051SMax Filippov bool dfpu = xtensa_option_enabled(env->config, 98cfa9f051SMax Filippov XTENSA_OPTION_DFP_COPROCESSOR); 99fcf5ef2aSThomas Huth 100d66e64ddSPeter Maydell if (xcc->parent_phases.hold) { 101d66e64ddSPeter Maydell xcc->parent_phases.hold(obj); 102d66e64ddSPeter Maydell } 103fcf5ef2aSThomas Huth 10417ab14acSMax Filippov env->pc = env->config->exception_vector[EXC_RESET0 + env->static_vectors]; 105fcf5ef2aSThomas Huth env->sregs[LITBASE] &= ~1; 106ba7651fbSMax Filippov #ifndef CONFIG_USER_ONLY 107fcf5ef2aSThomas Huth env->sregs[PS] = xtensa_option_enabled(env->config, 108fcf5ef2aSThomas Huth XTENSA_OPTION_INTERRUPT) ? 0x1f : 0x10; 109ba7651fbSMax Filippov env->pending_irq_level = 0; 110ba7651fbSMax Filippov #else 111130ea832SMax Filippov env->sregs[PS] = PS_UM | (3 << PS_RING_SHIFT); 112130ea832SMax Filippov if (xtensa_option_enabled(env->config, 113130ea832SMax Filippov XTENSA_OPTION_WINDOWED_REGISTER) && 114130ea832SMax Filippov !xtensa_abi_call0()) { 115130ea832SMax Filippov env->sregs[PS] |= PS_WOE; 116130ea832SMax Filippov } 117ab97f050SMax Filippov env->sregs[CPENABLE] = 0xff; 118ba7651fbSMax Filippov #endif 119fcf5ef2aSThomas Huth env->sregs[VECBASE] = env->config->vecbase; 120fcf5ef2aSThomas Huth env->sregs[IBREAKENABLE] = 0; 1219e03ade4SMax Filippov env->sregs[MEMCTL] = MEMCTL_IL0EN & env->config->memctl_mask; 122fcf5ef2aSThomas Huth env->sregs[ATOMCTL] = xtensa_option_enabled(env->config, 123fcf5ef2aSThomas Huth XTENSA_OPTION_ATOMCTL) ? 0x28 : 0x15; 124fcf5ef2aSThomas Huth env->sregs[CONFIGID0] = env->config->configid[0]; 125fcf5ef2aSThomas Huth env->sregs[CONFIGID1] = env->config->configid[1]; 126b345e140SMax Filippov env->exclusive_addr = -1; 127fcf5ef2aSThomas Huth 128ba7651fbSMax Filippov #ifndef CONFIG_USER_ONLY 129fcf5ef2aSThomas Huth reset_mmu(env); 130bd527a83SMax Filippov s->halted = env->runstall; 131ba7651fbSMax Filippov #endif 132cfa9f051SMax Filippov set_no_signaling_nans(!dfpu, &env->fp_status); 133cfa9f051SMax Filippov set_use_first_nan(!dfpu, &env->fp_status); 134fcf5ef2aSThomas Huth } 135fcf5ef2aSThomas Huth 136fcf5ef2aSThomas Huth static ObjectClass *xtensa_cpu_class_by_name(const char *cpu_model) 137fcf5ef2aSThomas Huth { 138fcf5ef2aSThomas Huth ObjectClass *oc; 139fcf5ef2aSThomas Huth char *typename; 140fcf5ef2aSThomas Huth 141a5247d76SIgor Mammedov typename = g_strdup_printf(XTENSA_CPU_TYPE_NAME("%s"), cpu_model); 142fcf5ef2aSThomas Huth oc = object_class_by_name(typename); 143fcf5ef2aSThomas Huth g_free(typename); 144fcf5ef2aSThomas Huth if (oc == NULL || !object_class_dynamic_cast(oc, TYPE_XTENSA_CPU) || 145fcf5ef2aSThomas Huth object_class_is_abstract(oc)) { 146fcf5ef2aSThomas Huth return NULL; 147fcf5ef2aSThomas Huth } 148fcf5ef2aSThomas Huth return oc; 149fcf5ef2aSThomas Huth } 150fcf5ef2aSThomas Huth 1515a6539e6SMax Filippov static void xtensa_cpu_disas_set_info(CPUState *cs, disassemble_info *info) 1525a6539e6SMax Filippov { 1535a6539e6SMax Filippov XtensaCPU *cpu = XTENSA_CPU(cs); 1545a6539e6SMax Filippov 1555a6539e6SMax Filippov info->private_data = cpu->env.config->isa; 1565a6539e6SMax Filippov info->print_insn = print_insn_xtensa; 1575a6539e6SMax Filippov } 1585a6539e6SMax Filippov 159fcf5ef2aSThomas Huth static void xtensa_cpu_realizefn(DeviceState *dev, Error **errp) 160fcf5ef2aSThomas Huth { 161fcf5ef2aSThomas Huth CPUState *cs = CPU(dev); 162fcf5ef2aSThomas Huth XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(dev); 163fcf5ef2aSThomas Huth Error *local_err = NULL; 164fcf5ef2aSThomas Huth 165ba7651fbSMax Filippov #ifndef CONFIG_USER_ONLY 166ba7651fbSMax Filippov xtensa_irq_init(&XTENSA_CPU(dev)->env); 167ba7651fbSMax Filippov #endif 1688e36271bSIgor Mammedov 169fcf5ef2aSThomas Huth cpu_exec_realizefn(cs, &local_err); 170fcf5ef2aSThomas Huth if (local_err != NULL) { 171fcf5ef2aSThomas Huth error_propagate(errp, local_err); 172fcf5ef2aSThomas Huth return; 173fcf5ef2aSThomas Huth } 174fcf5ef2aSThomas Huth 175fcf5ef2aSThomas Huth cs->gdb_num_regs = xcc->config->gdb_regmap.num_regs; 176fcf5ef2aSThomas Huth 177fcf5ef2aSThomas Huth qemu_init_vcpu(cs); 178fcf5ef2aSThomas Huth 179fcf5ef2aSThomas Huth xcc->parent_realize(dev, errp); 180fcf5ef2aSThomas Huth } 181fcf5ef2aSThomas Huth 182fcf5ef2aSThomas Huth static void xtensa_cpu_initfn(Object *obj) 183fcf5ef2aSThomas Huth { 184fcf5ef2aSThomas Huth XtensaCPU *cpu = XTENSA_CPU(obj); 185fcf5ef2aSThomas Huth XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(obj); 186fcf5ef2aSThomas Huth CPUXtensaState *env = &cpu->env; 187fcf5ef2aSThomas Huth 1887506ed90SRichard Henderson cpu_set_cpustate_pointers(cpu); 189fcf5ef2aSThomas Huth env->config = xcc->config; 190fcf5ef2aSThomas Huth 191ba7651fbSMax Filippov #ifndef CONFIG_USER_ONLY 1923a3c9dc4SMax Filippov env->address_space_er = g_malloc(sizeof(*env->address_space_er)); 1933a3c9dc4SMax Filippov env->system_er = g_malloc(sizeof(*env->system_er)); 19409d98b69SThomas Huth memory_region_init_io(env->system_er, obj, NULL, env, "er", 1953a3c9dc4SMax Filippov UINT64_C(0x100000000)); 1963a3c9dc4SMax Filippov address_space_init(env->address_space_er, env->system_er, "ER"); 1979e377be1SMax Filippov 1989e377be1SMax Filippov cpu->clock = qdev_init_clock_in(DEVICE(obj), "clk-in", NULL, cpu, 0); 1999e377be1SMax Filippov clock_set_hz(cpu->clock, env->config->clock_freq_khz * 1000); 200ba7651fbSMax Filippov #endif 201fcf5ef2aSThomas Huth } 202fcf5ef2aSThomas Huth 2039e377be1SMax Filippov XtensaCPU *xtensa_cpu_create_with_clock(const char *cpu_type, Clock *cpu_refclk) 2049e377be1SMax Filippov { 2059e377be1SMax Filippov DeviceState *cpu; 2069e377be1SMax Filippov 2079e377be1SMax Filippov cpu = DEVICE(object_new(cpu_type)); 2089e377be1SMax Filippov qdev_connect_clock_in(cpu, "clk-in", cpu_refclk); 2099e377be1SMax Filippov qdev_realize(cpu, NULL, &error_abort); 2109e377be1SMax Filippov 2119e377be1SMax Filippov return XTENSA_CPU(cpu); 2129e377be1SMax Filippov } 2139e377be1SMax Filippov 2144336073bSPhilippe Mathieu-Daudé #ifndef CONFIG_USER_ONLY 215fcf5ef2aSThomas Huth static const VMStateDescription vmstate_xtensa_cpu = { 216fcf5ef2aSThomas Huth .name = "cpu", 217fcf5ef2aSThomas Huth .unmigratable = 1, 218fcf5ef2aSThomas Huth }; 2198b80bd28SPhilippe Mathieu-Daudé 2208b80bd28SPhilippe Mathieu-Daudé #include "hw/core/sysemu-cpu-ops.h" 2218b80bd28SPhilippe Mathieu-Daudé 2228b80bd28SPhilippe Mathieu-Daudé static const struct SysemuCPUOps xtensa_sysemu_ops = { 22308928c6dSPhilippe Mathieu-Daudé .get_phys_page_debug = xtensa_cpu_get_phys_page_debug, 2248b80bd28SPhilippe Mathieu-Daudé }; 2254336073bSPhilippe Mathieu-Daudé #endif 226fcf5ef2aSThomas Huth 22778271684SClaudio Fontana #include "hw/core/tcg-cpu-ops.h" 22878271684SClaudio Fontana 22911906557SRichard Henderson static const struct TCGCPUOps xtensa_tcg_ops = { 23078271684SClaudio Fontana .initialize = xtensa_translate_init, 23178271684SClaudio Fontana .debug_excp_handler = xtensa_breakpoint_handler, 232044dcfc5SRichard Henderson .restore_state_to_opc = xtensa_restore_state_to_opc, 23378271684SClaudio Fontana 23478271684SClaudio Fontana #ifndef CONFIG_USER_ONLY 2356407f64fSRichard Henderson .tlb_fill = xtensa_cpu_tlb_fill, 236f364a7f9SPhilippe Mathieu-Daudé .cpu_exec_interrupt = xtensa_cpu_exec_interrupt, 23778271684SClaudio Fontana .do_interrupt = xtensa_cpu_do_interrupt, 23878271684SClaudio Fontana .do_transaction_failed = xtensa_cpu_do_transaction_failed, 23978271684SClaudio Fontana .do_unaligned_access = xtensa_cpu_do_unaligned_access, 24078271684SClaudio Fontana #endif /* !CONFIG_USER_ONLY */ 24178271684SClaudio Fontana }; 24278271684SClaudio Fontana 243fcf5ef2aSThomas Huth static void xtensa_cpu_class_init(ObjectClass *oc, void *data) 244fcf5ef2aSThomas Huth { 245fcf5ef2aSThomas Huth DeviceClass *dc = DEVICE_CLASS(oc); 246fcf5ef2aSThomas Huth CPUClass *cc = CPU_CLASS(oc); 247fcf5ef2aSThomas Huth XtensaCPUClass *xcc = XTENSA_CPU_CLASS(cc); 248d66e64ddSPeter Maydell ResettableClass *rc = RESETTABLE_CLASS(oc); 249fcf5ef2aSThomas Huth 250bf853881SPhilippe Mathieu-Daudé device_class_set_parent_realize(dc, xtensa_cpu_realizefn, 251bf853881SPhilippe Mathieu-Daudé &xcc->parent_realize); 252fcf5ef2aSThomas Huth 253d66e64ddSPeter Maydell resettable_class_set_parent_phases(rc, NULL, xtensa_cpu_reset_hold, NULL, 254d66e64ddSPeter Maydell &xcc->parent_phases); 255fcf5ef2aSThomas Huth 256fcf5ef2aSThomas Huth cc->class_by_name = xtensa_cpu_class_by_name; 257fcf5ef2aSThomas Huth cc->has_work = xtensa_cpu_has_work; 258fcf5ef2aSThomas Huth cc->dump_state = xtensa_cpu_dump_state; 259fcf5ef2aSThomas Huth cc->set_pc = xtensa_cpu_set_pc; 260e4fdf9dfSRichard Henderson cc->get_pc = xtensa_cpu_get_pc; 261fcf5ef2aSThomas Huth cc->gdb_read_register = xtensa_cpu_gdb_read_register; 262fcf5ef2aSThomas Huth cc->gdb_write_register = xtensa_cpu_gdb_write_register; 263fcf5ef2aSThomas Huth cc->gdb_stop_before_watchpoint = true; 264b008c456SRichard Henderson #ifndef CONFIG_USER_ONLY 2658b80bd28SPhilippe Mathieu-Daudé cc->sysemu_ops = &xtensa_sysemu_ops; 2664336073bSPhilippe Mathieu-Daudé dc->vmsd = &vmstate_xtensa_cpu; 267fcf5ef2aSThomas Huth #endif 2685a6539e6SMax Filippov cc->disas_set_info = xtensa_cpu_disas_set_info; 26978271684SClaudio Fontana cc->tcg_ops = &xtensa_tcg_ops; 270fcf5ef2aSThomas Huth } 271fcf5ef2aSThomas Huth 272fcf5ef2aSThomas Huth static const TypeInfo xtensa_cpu_type_info = { 273fcf5ef2aSThomas Huth .name = TYPE_XTENSA_CPU, 274fcf5ef2aSThomas Huth .parent = TYPE_CPU, 275fcf5ef2aSThomas Huth .instance_size = sizeof(XtensaCPU), 276*f669c992SRichard Henderson .instance_align = __alignof(XtensaCPU), 277fcf5ef2aSThomas Huth .instance_init = xtensa_cpu_initfn, 278fcf5ef2aSThomas Huth .abstract = true, 279fcf5ef2aSThomas Huth .class_size = sizeof(XtensaCPUClass), 280fcf5ef2aSThomas Huth .class_init = xtensa_cpu_class_init, 281fcf5ef2aSThomas Huth }; 282fcf5ef2aSThomas Huth 283fcf5ef2aSThomas Huth static void xtensa_cpu_register_types(void) 284fcf5ef2aSThomas Huth { 285fcf5ef2aSThomas Huth type_register_static(&xtensa_cpu_type_info); 286fcf5ef2aSThomas Huth } 287fcf5ef2aSThomas Huth 288fcf5ef2aSThomas Huth type_init(xtensa_cpu_register_types) 289