1*45183ccdSTaylor Simpson /* 2*45183ccdSTaylor Simpson * Copyright(c) 2019-2021 Qualcomm Innovation Center, Inc. All Rights Reserved. 3*45183ccdSTaylor Simpson * 4*45183ccdSTaylor Simpson * This program is free software; you can redistribute it and/or modify 5*45183ccdSTaylor Simpson * it under the terms of the GNU General Public License as published by 6*45183ccdSTaylor Simpson * the Free Software Foundation; either version 2 of the License, or 7*45183ccdSTaylor Simpson * (at your option) any later version. 8*45183ccdSTaylor Simpson * 9*45183ccdSTaylor Simpson * This program is distributed in the hope that it will be useful, 10*45183ccdSTaylor Simpson * but WITHOUT ANY WARRANTY; without even the implied warranty of 11*45183ccdSTaylor Simpson * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12*45183ccdSTaylor Simpson * GNU General Public License for more details. 13*45183ccdSTaylor Simpson * 14*45183ccdSTaylor Simpson * You should have received a copy of the GNU General Public License 15*45183ccdSTaylor Simpson * along with this program; if not, see <http://www.gnu.org/licenses/>. 16*45183ccdSTaylor Simpson */ 17*45183ccdSTaylor Simpson 18*45183ccdSTaylor Simpson #include "qemu/osdep.h" 19*45183ccdSTaylor Simpson #include "qemu/log.h" 20*45183ccdSTaylor Simpson #include "qemu/qemu-print.h" 21*45183ccdSTaylor Simpson #include "cpu.h" 22*45183ccdSTaylor Simpson #include "internal.h" 23*45183ccdSTaylor Simpson #include "exec/exec-all.h" 24*45183ccdSTaylor Simpson #include "qapi/error.h" 25*45183ccdSTaylor Simpson #include "hw/qdev-properties.h" 26*45183ccdSTaylor Simpson 27*45183ccdSTaylor Simpson static void hexagon_v67_cpu_init(Object *obj) 28*45183ccdSTaylor Simpson { 29*45183ccdSTaylor Simpson } 30*45183ccdSTaylor Simpson 31*45183ccdSTaylor Simpson static ObjectClass *hexagon_cpu_class_by_name(const char *cpu_model) 32*45183ccdSTaylor Simpson { 33*45183ccdSTaylor Simpson ObjectClass *oc; 34*45183ccdSTaylor Simpson char *typename; 35*45183ccdSTaylor Simpson char **cpuname; 36*45183ccdSTaylor Simpson 37*45183ccdSTaylor Simpson cpuname = g_strsplit(cpu_model, ",", 1); 38*45183ccdSTaylor Simpson typename = g_strdup_printf(HEXAGON_CPU_TYPE_NAME("%s"), cpuname[0]); 39*45183ccdSTaylor Simpson oc = object_class_by_name(typename); 40*45183ccdSTaylor Simpson g_strfreev(cpuname); 41*45183ccdSTaylor Simpson g_free(typename); 42*45183ccdSTaylor Simpson if (!oc || !object_class_dynamic_cast(oc, TYPE_HEXAGON_CPU) || 43*45183ccdSTaylor Simpson object_class_is_abstract(oc)) { 44*45183ccdSTaylor Simpson return NULL; 45*45183ccdSTaylor Simpson } 46*45183ccdSTaylor Simpson return oc; 47*45183ccdSTaylor Simpson } 48*45183ccdSTaylor Simpson 49*45183ccdSTaylor Simpson static Property hexagon_lldb_compat_property = 50*45183ccdSTaylor Simpson DEFINE_PROP_BOOL("lldb-compat", HexagonCPU, lldb_compat, false); 51*45183ccdSTaylor Simpson static Property hexagon_lldb_stack_adjust_property = 52*45183ccdSTaylor Simpson DEFINE_PROP_UNSIGNED("lldb-stack-adjust", HexagonCPU, lldb_stack_adjust, 53*45183ccdSTaylor Simpson 0, qdev_prop_uint32, target_ulong); 54*45183ccdSTaylor Simpson 55*45183ccdSTaylor Simpson const char * const hexagon_regnames[TOTAL_PER_THREAD_REGS] = { 56*45183ccdSTaylor Simpson "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", 57*45183ccdSTaylor Simpson "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", 58*45183ccdSTaylor Simpson "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", 59*45183ccdSTaylor Simpson "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", 60*45183ccdSTaylor Simpson "sa0", "lc0", "sa1", "lc1", "p3_0", "c5", "m0", "m1", 61*45183ccdSTaylor Simpson "usr", "pc", "ugp", "gp", "cs0", "cs1", "c14", "c15", 62*45183ccdSTaylor Simpson "c16", "c17", "c18", "c19", "pkt_cnt", "insn_cnt", "c22", "c23", 63*45183ccdSTaylor Simpson "c24", "c25", "c26", "c27", "c28", "c29", "c30", "c31", 64*45183ccdSTaylor Simpson }; 65*45183ccdSTaylor Simpson 66*45183ccdSTaylor Simpson /* 67*45183ccdSTaylor Simpson * One of the main debugging techniques is to use "-d cpu" and compare against 68*45183ccdSTaylor Simpson * LLDB output when single stepping. However, the target and qemu put the 69*45183ccdSTaylor Simpson * stacks at different locations. This is used to compensate so the diff is 70*45183ccdSTaylor Simpson * cleaner. 71*45183ccdSTaylor Simpson */ 72*45183ccdSTaylor Simpson static inline target_ulong adjust_stack_ptrs(CPUHexagonState *env, 73*45183ccdSTaylor Simpson target_ulong addr) 74*45183ccdSTaylor Simpson { 75*45183ccdSTaylor Simpson HexagonCPU *cpu = container_of(env, HexagonCPU, env); 76*45183ccdSTaylor Simpson target_ulong stack_adjust = cpu->lldb_stack_adjust; 77*45183ccdSTaylor Simpson target_ulong stack_start = env->stack_start; 78*45183ccdSTaylor Simpson target_ulong stack_size = 0x10000; 79*45183ccdSTaylor Simpson 80*45183ccdSTaylor Simpson if (stack_adjust == 0) { 81*45183ccdSTaylor Simpson return addr; 82*45183ccdSTaylor Simpson } 83*45183ccdSTaylor Simpson 84*45183ccdSTaylor Simpson if (stack_start + 0x1000 >= addr && addr >= (stack_start - stack_size)) { 85*45183ccdSTaylor Simpson return addr - stack_adjust; 86*45183ccdSTaylor Simpson } 87*45183ccdSTaylor Simpson return addr; 88*45183ccdSTaylor Simpson } 89*45183ccdSTaylor Simpson 90*45183ccdSTaylor Simpson /* HEX_REG_P3_0 (aka C4) is an alias for the predicate registers */ 91*45183ccdSTaylor Simpson static inline target_ulong read_p3_0(CPUHexagonState *env) 92*45183ccdSTaylor Simpson { 93*45183ccdSTaylor Simpson int32_t control_reg = 0; 94*45183ccdSTaylor Simpson int i; 95*45183ccdSTaylor Simpson for (i = NUM_PREGS - 1; i >= 0; i--) { 96*45183ccdSTaylor Simpson control_reg <<= 8; 97*45183ccdSTaylor Simpson control_reg |= env->pred[i] & 0xff; 98*45183ccdSTaylor Simpson } 99*45183ccdSTaylor Simpson return control_reg; 100*45183ccdSTaylor Simpson } 101*45183ccdSTaylor Simpson 102*45183ccdSTaylor Simpson static void print_reg(FILE *f, CPUHexagonState *env, int regnum) 103*45183ccdSTaylor Simpson { 104*45183ccdSTaylor Simpson target_ulong value; 105*45183ccdSTaylor Simpson 106*45183ccdSTaylor Simpson if (regnum == HEX_REG_P3_0) { 107*45183ccdSTaylor Simpson value = read_p3_0(env); 108*45183ccdSTaylor Simpson } else { 109*45183ccdSTaylor Simpson value = regnum < 32 ? adjust_stack_ptrs(env, env->gpr[regnum]) 110*45183ccdSTaylor Simpson : env->gpr[regnum]; 111*45183ccdSTaylor Simpson } 112*45183ccdSTaylor Simpson 113*45183ccdSTaylor Simpson qemu_fprintf(f, " %s = 0x" TARGET_FMT_lx "\n", 114*45183ccdSTaylor Simpson hexagon_regnames[regnum], value); 115*45183ccdSTaylor Simpson } 116*45183ccdSTaylor Simpson 117*45183ccdSTaylor Simpson static void hexagon_dump(CPUHexagonState *env, FILE *f) 118*45183ccdSTaylor Simpson { 119*45183ccdSTaylor Simpson HexagonCPU *cpu = container_of(env, HexagonCPU, env); 120*45183ccdSTaylor Simpson 121*45183ccdSTaylor Simpson if (cpu->lldb_compat) { 122*45183ccdSTaylor Simpson /* 123*45183ccdSTaylor Simpson * When comparing with LLDB, it doesn't step through single-cycle 124*45183ccdSTaylor Simpson * hardware loops the same way. So, we just skip them here 125*45183ccdSTaylor Simpson */ 126*45183ccdSTaylor Simpson if (env->gpr[HEX_REG_PC] == env->last_pc_dumped) { 127*45183ccdSTaylor Simpson return; 128*45183ccdSTaylor Simpson } 129*45183ccdSTaylor Simpson env->last_pc_dumped = env->gpr[HEX_REG_PC]; 130*45183ccdSTaylor Simpson } 131*45183ccdSTaylor Simpson 132*45183ccdSTaylor Simpson qemu_fprintf(f, "General Purpose Registers = {\n"); 133*45183ccdSTaylor Simpson for (int i = 0; i < 32; i++) { 134*45183ccdSTaylor Simpson print_reg(f, env, i); 135*45183ccdSTaylor Simpson } 136*45183ccdSTaylor Simpson print_reg(f, env, HEX_REG_SA0); 137*45183ccdSTaylor Simpson print_reg(f, env, HEX_REG_LC0); 138*45183ccdSTaylor Simpson print_reg(f, env, HEX_REG_SA1); 139*45183ccdSTaylor Simpson print_reg(f, env, HEX_REG_LC1); 140*45183ccdSTaylor Simpson print_reg(f, env, HEX_REG_M0); 141*45183ccdSTaylor Simpson print_reg(f, env, HEX_REG_M1); 142*45183ccdSTaylor Simpson print_reg(f, env, HEX_REG_USR); 143*45183ccdSTaylor Simpson print_reg(f, env, HEX_REG_P3_0); 144*45183ccdSTaylor Simpson print_reg(f, env, HEX_REG_GP); 145*45183ccdSTaylor Simpson print_reg(f, env, HEX_REG_UGP); 146*45183ccdSTaylor Simpson print_reg(f, env, HEX_REG_PC); 147*45183ccdSTaylor Simpson #ifdef CONFIG_USER_ONLY 148*45183ccdSTaylor Simpson /* 149*45183ccdSTaylor Simpson * Not modelled in user mode, print junk to minimize the diff's 150*45183ccdSTaylor Simpson * with LLDB output 151*45183ccdSTaylor Simpson */ 152*45183ccdSTaylor Simpson qemu_fprintf(f, " cause = 0x000000db\n"); 153*45183ccdSTaylor Simpson qemu_fprintf(f, " badva = 0x00000000\n"); 154*45183ccdSTaylor Simpson qemu_fprintf(f, " cs0 = 0x00000000\n"); 155*45183ccdSTaylor Simpson qemu_fprintf(f, " cs1 = 0x00000000\n"); 156*45183ccdSTaylor Simpson #else 157*45183ccdSTaylor Simpson print_reg(f, env, HEX_REG_CAUSE); 158*45183ccdSTaylor Simpson print_reg(f, env, HEX_REG_BADVA); 159*45183ccdSTaylor Simpson print_reg(f, env, HEX_REG_CS0); 160*45183ccdSTaylor Simpson print_reg(f, env, HEX_REG_CS1); 161*45183ccdSTaylor Simpson #endif 162*45183ccdSTaylor Simpson qemu_fprintf(f, "}\n"); 163*45183ccdSTaylor Simpson } 164*45183ccdSTaylor Simpson 165*45183ccdSTaylor Simpson static void hexagon_dump_state(CPUState *cs, FILE *f, int flags) 166*45183ccdSTaylor Simpson { 167*45183ccdSTaylor Simpson HexagonCPU *cpu = HEXAGON_CPU(cs); 168*45183ccdSTaylor Simpson CPUHexagonState *env = &cpu->env; 169*45183ccdSTaylor Simpson 170*45183ccdSTaylor Simpson hexagon_dump(env, f); 171*45183ccdSTaylor Simpson } 172*45183ccdSTaylor Simpson 173*45183ccdSTaylor Simpson void hexagon_debug(CPUHexagonState *env) 174*45183ccdSTaylor Simpson { 175*45183ccdSTaylor Simpson hexagon_dump(env, stdout); 176*45183ccdSTaylor Simpson } 177*45183ccdSTaylor Simpson 178*45183ccdSTaylor Simpson static void hexagon_cpu_set_pc(CPUState *cs, vaddr value) 179*45183ccdSTaylor Simpson { 180*45183ccdSTaylor Simpson HexagonCPU *cpu = HEXAGON_CPU(cs); 181*45183ccdSTaylor Simpson CPUHexagonState *env = &cpu->env; 182*45183ccdSTaylor Simpson env->gpr[HEX_REG_PC] = value; 183*45183ccdSTaylor Simpson } 184*45183ccdSTaylor Simpson 185*45183ccdSTaylor Simpson static void hexagon_cpu_synchronize_from_tb(CPUState *cs, 186*45183ccdSTaylor Simpson const TranslationBlock *tb) 187*45183ccdSTaylor Simpson { 188*45183ccdSTaylor Simpson HexagonCPU *cpu = HEXAGON_CPU(cs); 189*45183ccdSTaylor Simpson CPUHexagonState *env = &cpu->env; 190*45183ccdSTaylor Simpson env->gpr[HEX_REG_PC] = tb->pc; 191*45183ccdSTaylor Simpson } 192*45183ccdSTaylor Simpson 193*45183ccdSTaylor Simpson static bool hexagon_cpu_has_work(CPUState *cs) 194*45183ccdSTaylor Simpson { 195*45183ccdSTaylor Simpson return true; 196*45183ccdSTaylor Simpson } 197*45183ccdSTaylor Simpson 198*45183ccdSTaylor Simpson void restore_state_to_opc(CPUHexagonState *env, TranslationBlock *tb, 199*45183ccdSTaylor Simpson target_ulong *data) 200*45183ccdSTaylor Simpson { 201*45183ccdSTaylor Simpson env->gpr[HEX_REG_PC] = data[0]; 202*45183ccdSTaylor Simpson } 203*45183ccdSTaylor Simpson 204*45183ccdSTaylor Simpson static void hexagon_cpu_reset(DeviceState *dev) 205*45183ccdSTaylor Simpson { 206*45183ccdSTaylor Simpson CPUState *cs = CPU(dev); 207*45183ccdSTaylor Simpson HexagonCPU *cpu = HEXAGON_CPU(cs); 208*45183ccdSTaylor Simpson HexagonCPUClass *mcc = HEXAGON_CPU_GET_CLASS(cpu); 209*45183ccdSTaylor Simpson 210*45183ccdSTaylor Simpson mcc->parent_reset(dev); 211*45183ccdSTaylor Simpson } 212*45183ccdSTaylor Simpson 213*45183ccdSTaylor Simpson static void hexagon_cpu_disas_set_info(CPUState *s, disassemble_info *info) 214*45183ccdSTaylor Simpson { 215*45183ccdSTaylor Simpson info->print_insn = print_insn_hexagon; 216*45183ccdSTaylor Simpson } 217*45183ccdSTaylor Simpson 218*45183ccdSTaylor Simpson static void hexagon_cpu_realize(DeviceState *dev, Error **errp) 219*45183ccdSTaylor Simpson { 220*45183ccdSTaylor Simpson CPUState *cs = CPU(dev); 221*45183ccdSTaylor Simpson HexagonCPUClass *mcc = HEXAGON_CPU_GET_CLASS(dev); 222*45183ccdSTaylor Simpson Error *local_err = NULL; 223*45183ccdSTaylor Simpson 224*45183ccdSTaylor Simpson cpu_exec_realizefn(cs, &local_err); 225*45183ccdSTaylor Simpson if (local_err != NULL) { 226*45183ccdSTaylor Simpson error_propagate(errp, local_err); 227*45183ccdSTaylor Simpson return; 228*45183ccdSTaylor Simpson } 229*45183ccdSTaylor Simpson 230*45183ccdSTaylor Simpson qemu_init_vcpu(cs); 231*45183ccdSTaylor Simpson cpu_reset(cs); 232*45183ccdSTaylor Simpson 233*45183ccdSTaylor Simpson mcc->parent_realize(dev, errp); 234*45183ccdSTaylor Simpson } 235*45183ccdSTaylor Simpson 236*45183ccdSTaylor Simpson static void hexagon_cpu_init(Object *obj) 237*45183ccdSTaylor Simpson { 238*45183ccdSTaylor Simpson HexagonCPU *cpu = HEXAGON_CPU(obj); 239*45183ccdSTaylor Simpson 240*45183ccdSTaylor Simpson cpu_set_cpustate_pointers(cpu); 241*45183ccdSTaylor Simpson qdev_property_add_static(DEVICE(obj), &hexagon_lldb_compat_property); 242*45183ccdSTaylor Simpson qdev_property_add_static(DEVICE(obj), &hexagon_lldb_stack_adjust_property); 243*45183ccdSTaylor Simpson } 244*45183ccdSTaylor Simpson 245*45183ccdSTaylor Simpson static bool hexagon_tlb_fill(CPUState *cs, vaddr address, int size, 246*45183ccdSTaylor Simpson MMUAccessType access_type, int mmu_idx, 247*45183ccdSTaylor Simpson bool probe, uintptr_t retaddr) 248*45183ccdSTaylor Simpson { 249*45183ccdSTaylor Simpson #ifdef CONFIG_USER_ONLY 250*45183ccdSTaylor Simpson switch (access_type) { 251*45183ccdSTaylor Simpson case MMU_INST_FETCH: 252*45183ccdSTaylor Simpson cs->exception_index = HEX_EXCP_FETCH_NO_UPAGE; 253*45183ccdSTaylor Simpson break; 254*45183ccdSTaylor Simpson case MMU_DATA_LOAD: 255*45183ccdSTaylor Simpson cs->exception_index = HEX_EXCP_PRIV_NO_UREAD; 256*45183ccdSTaylor Simpson break; 257*45183ccdSTaylor Simpson case MMU_DATA_STORE: 258*45183ccdSTaylor Simpson cs->exception_index = HEX_EXCP_PRIV_NO_UWRITE; 259*45183ccdSTaylor Simpson break; 260*45183ccdSTaylor Simpson } 261*45183ccdSTaylor Simpson cpu_loop_exit_restore(cs, retaddr); 262*45183ccdSTaylor Simpson #else 263*45183ccdSTaylor Simpson #error System mode not implemented for Hexagon 264*45183ccdSTaylor Simpson #endif 265*45183ccdSTaylor Simpson } 266*45183ccdSTaylor Simpson 267*45183ccdSTaylor Simpson #include "hw/core/tcg-cpu-ops.h" 268*45183ccdSTaylor Simpson 269*45183ccdSTaylor Simpson static struct TCGCPUOps hexagon_tcg_ops = { 270*45183ccdSTaylor Simpson .initialize = hexagon_translate_init, 271*45183ccdSTaylor Simpson .synchronize_from_tb = hexagon_cpu_synchronize_from_tb, 272*45183ccdSTaylor Simpson .tlb_fill = hexagon_tlb_fill, 273*45183ccdSTaylor Simpson }; 274*45183ccdSTaylor Simpson 275*45183ccdSTaylor Simpson static void hexagon_cpu_class_init(ObjectClass *c, void *data) 276*45183ccdSTaylor Simpson { 277*45183ccdSTaylor Simpson HexagonCPUClass *mcc = HEXAGON_CPU_CLASS(c); 278*45183ccdSTaylor Simpson CPUClass *cc = CPU_CLASS(c); 279*45183ccdSTaylor Simpson DeviceClass *dc = DEVICE_CLASS(c); 280*45183ccdSTaylor Simpson 281*45183ccdSTaylor Simpson device_class_set_parent_realize(dc, hexagon_cpu_realize, 282*45183ccdSTaylor Simpson &mcc->parent_realize); 283*45183ccdSTaylor Simpson 284*45183ccdSTaylor Simpson device_class_set_parent_reset(dc, hexagon_cpu_reset, &mcc->parent_reset); 285*45183ccdSTaylor Simpson 286*45183ccdSTaylor Simpson cc->class_by_name = hexagon_cpu_class_by_name; 287*45183ccdSTaylor Simpson cc->has_work = hexagon_cpu_has_work; 288*45183ccdSTaylor Simpson cc->dump_state = hexagon_dump_state; 289*45183ccdSTaylor Simpson cc->set_pc = hexagon_cpu_set_pc; 290*45183ccdSTaylor Simpson cc->gdb_read_register = hexagon_gdb_read_register; 291*45183ccdSTaylor Simpson cc->gdb_write_register = hexagon_gdb_write_register; 292*45183ccdSTaylor Simpson cc->gdb_num_core_regs = TOTAL_PER_THREAD_REGS; 293*45183ccdSTaylor Simpson cc->gdb_stop_before_watchpoint = true; 294*45183ccdSTaylor Simpson cc->disas_set_info = hexagon_cpu_disas_set_info; 295*45183ccdSTaylor Simpson cc->tcg_ops = &hexagon_tcg_ops; 296*45183ccdSTaylor Simpson } 297*45183ccdSTaylor Simpson 298*45183ccdSTaylor Simpson #define DEFINE_CPU(type_name, initfn) \ 299*45183ccdSTaylor Simpson { \ 300*45183ccdSTaylor Simpson .name = type_name, \ 301*45183ccdSTaylor Simpson .parent = TYPE_HEXAGON_CPU, \ 302*45183ccdSTaylor Simpson .instance_init = initfn \ 303*45183ccdSTaylor Simpson } 304*45183ccdSTaylor Simpson 305*45183ccdSTaylor Simpson static const TypeInfo hexagon_cpu_type_infos[] = { 306*45183ccdSTaylor Simpson { 307*45183ccdSTaylor Simpson .name = TYPE_HEXAGON_CPU, 308*45183ccdSTaylor Simpson .parent = TYPE_CPU, 309*45183ccdSTaylor Simpson .instance_size = sizeof(HexagonCPU), 310*45183ccdSTaylor Simpson .instance_init = hexagon_cpu_init, 311*45183ccdSTaylor Simpson .abstract = true, 312*45183ccdSTaylor Simpson .class_size = sizeof(HexagonCPUClass), 313*45183ccdSTaylor Simpson .class_init = hexagon_cpu_class_init, 314*45183ccdSTaylor Simpson }, 315*45183ccdSTaylor Simpson DEFINE_CPU(TYPE_HEXAGON_CPU_V67, hexagon_v67_cpu_init), 316*45183ccdSTaylor Simpson }; 317*45183ccdSTaylor Simpson 318*45183ccdSTaylor Simpson DEFINE_TYPES(hexagon_cpu_type_infos) 319