From patchwork Tue Jul 7 18:16:40 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= X-Patchwork-Id: 1324567 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=amsat.org Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20161025 header.b=VGS0bYZs; dkim-atps=neutral Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4B1VzL3C6Jz9sRN for ; Wed, 8 Jul 2020 04:17:50 +1000 (AEST) Received: from localhost ([::1]:37652 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jssA8-0007JM-1y for incoming@patchwork.ozlabs.org; Tue, 07 Jul 2020 14:17:48 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:35392) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1jss9g-0007HL-Sc for qemu-devel@nongnu.org; Tue, 07 Jul 2020 14:17:20 -0400 Received: from mail-wr1-x42e.google.com ([2a00:1450:4864:20::42e]:40008) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1jss9e-0002rP-Nh for qemu-devel@nongnu.org; Tue, 07 Jul 2020 14:17:20 -0400 Received: by mail-wr1-x42e.google.com with SMTP id f2so18254392wrp.7 for ; Tue, 07 Jul 2020 11:17:18 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=HxXiYJ5rEmrQsi6qo/9ibwEuycOoYFRspX6MfnrTd1Q=; b=VGS0bYZsfW/uMnD5Cemo6obLjJY/yYmxDv1SqkPS6Gh8+2z0QitXp1r4Xo5zkPjtOq JKE5yhK2sTD8HQz/gPhfd9kbRMUY9E1k3PKiR9sFP0kuvX8tdmea0TM7a5RcxgNQOHDQ rSVuEKs5m9xnwKKARcEs17gQiqQfPCnRw8uHAjV2ueR+VXQWDdpDqKlaCXrmXDsAMsML J+m6NjZyGycKy9vZi7+amEQiJpcRDXqb228PKi89CrFqSkQFLw0hkr4TI49otwaxs7fm zw+1uMP9nze/8OoHvO+pF/3V4YkYbDxxHWLnnhGnMKaPtwCv/TRAUSaUSFkYt+45itb6 XHzg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:from:to:cc:subject:date:message-id :in-reply-to:references:mime-version:content-transfer-encoding; bh=HxXiYJ5rEmrQsi6qo/9ibwEuycOoYFRspX6MfnrTd1Q=; b=MWZd0+D6c4Y2J8PsX88C8ZxDB/4mGrMXZ4HAxIIOEhCVRyyDW6BdFBz8XV7yiEwe0v Lbq+4IRl716CE7AQW/bnfsGGfLYu/82Lb+YlyAzabhqXABPDbdbjbwgkIjjR5JoSEYpD K8kaPlsez9FWKbTqPcRpk27p/9ERF+sqrDeyzDvGnWxtUu2JbIbKE6CoRZWaQWjnuEJD VIdC/44kqo0R54NpIYqvxZTF4BXcYXogv6tal56St7lV8hLwQL5EMx19fLeNng2nIeBS 5Zjtgxjx5f73I3UIeb5rIoQprfotqmuYsa1B80vC/5xXVgVTOuzu8qTZlGmV9uwm/qAu v/qQ== X-Gm-Message-State: AOAM5319J9RtI5rOkm7irKyHVWIOKVghRZ12x9+w762n4ELEMq54Z/sF GuOEqb8t+FFc7MD60vMlv1HHn4go X-Google-Smtp-Source: ABdhPJzmsAcE0ZMAgI0gwNOegFCAxC+/bhFhohyzwrNkZvxIT42VxSTEvdVhvit8TueslTvmccI9lQ== X-Received: by 2002:adf:f504:: with SMTP id q4mr54066286wro.163.1594145836615; Tue, 07 Jul 2020 11:17:16 -0700 (PDT) Received: from localhost.localdomain (138.red-83-57-170.dynamicip.rima-tde.net. [83.57.170.138]) by smtp.gmail.com with ESMTPSA id 65sm2253337wma.48.2020.07.07.11.17.15 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 07 Jul 2020 11:17:15 -0700 (PDT) From: =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= To: qemu-devel@nongnu.org Subject: [PULL 02/32] target/avr: Introduce basic CPU class object Date: Tue, 7 Jul 2020 20:16:40 +0200 Message-Id: <20200707181710.30950-3-f4bug@amsat.org> X-Mailer: git-send-email 2.21.3 In-Reply-To: <20200707181710.30950-1-f4bug@amsat.org> References: <20200707181710.30950-1-f4bug@amsat.org> MIME-Version: 1.0 Received-SPF: pass client-ip=2a00:1450:4864:20::42e; envelope-from=philippe.mathieu.daude@gmail.com; helo=mail-wr1-x42e.google.com X-detected-operating-system: by eggs.gnu.org: No matching host in p0f cache. That's all we know. X-Spam_score_int: 0 X-Spam_score: 0.0 X-Spam_bar: / X-Spam_report: (0.0 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FORGED_FROMDOMAIN=1, FREEMAIL_FROM=0.001, HEADER_FROM_DIFFERENT_DOMAINS=1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=_AUTOLEARN X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Laurent Vivier , Sarah Harris , Eduardo Habkost , Igor Mammedov , Thomas Huth , =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= , Cleber Rosa , Richard Henderson , Markus Armbruster , Wainer dos Santos Moschetta , Thomas Huth , =?utf-8?q?Alex_Benn=C3=A9e?= , Michael Rolnik , Paolo Bonzini , Pavel Dovgalyuk , =?utf-8?q?Marc-Andr=C3=A9_Lurea?= =?utf-8?q?u?= , =?utf-8?q?Philippe_Mathieu-Dau?= =?utf-8?q?d=C3=A9?= , Aleksandar Markovic , Richard Henderson Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" From: Michael Rolnik This patch introduces AVR CPU class object and its basic elements and functions. [AM: Split a larger AVR introduction patch into logical units] Suggested-by: Aleksandar Markovic Co-developed-by: Michael Rolnik Co-developed-by: Sarah Harris Signed-off-by: Michael Rolnik Signed-off-by: Sarah Harris Signed-off-by: Richard Henderson Signed-off-by: Aleksandar Markovic Acked-by: Igor Mammedov Tested-by: Philippe Mathieu-Daudé [thuth: Adjusted reset and parent_reset handling] Signed-off-by: Thomas Huth Message-Id: <20200705140315.260514-3-huth@tuxfamily.org> Signed-off-by: Philippe Mathieu-Daudé --- target/avr/cpu-qom.h | 54 +++++++++++ target/avr/cpu.h | 139 +++++++++++++++++++++++++++++ target/avr/cpu.c | 207 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 400 insertions(+) create mode 100644 target/avr/cpu-qom.h create mode 100644 target/avr/cpu.c diff --git a/target/avr/cpu-qom.h b/target/avr/cpu-qom.h new file mode 100644 index 0000000000..c3d0b7401c --- /dev/null +++ b/target/avr/cpu-qom.h @@ -0,0 +1,54 @@ +/* + * QEMU AVR CPU + * + * Copyright (c) 2016-2020 Michael Rolnik + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + * + */ + +#ifndef QEMU_AVR_QOM_H +#define QEMU_AVR_QOM_H + +#include "hw/core/cpu.h" + +#define TYPE_AVR_CPU "avr-cpu" + +#define AVR_CPU_CLASS(klass) \ + OBJECT_CLASS_CHECK(AVRCPUClass, (klass), TYPE_AVR_CPU) +#define AVR_CPU(obj) \ + OBJECT_CHECK(AVRCPU, (obj), TYPE_AVR_CPU) +#define AVR_CPU_GET_CLASS(obj) \ + OBJECT_GET_CLASS(AVRCPUClass, (obj), TYPE_AVR_CPU) + +/** + * AVRCPUClass: + * @parent_realize: The parent class' realize handler. + * @parent_reset: The parent class' reset handler. + * @vr: Version Register value. + * + * A AVR CPU model. + */ +typedef struct AVRCPUClass { + /*< private >*/ + CPUClass parent_class; + /*< public >*/ + DeviceRealize parent_realize; + DeviceReset parent_reset; +} AVRCPUClass; + +typedef struct AVRCPU AVRCPU; + + +#endif /* !defined (QEMU_AVR_CPU_QOM_H) */ diff --git a/target/avr/cpu.h b/target/avr/cpu.h index 45a87c5452..bac12dc684 100644 --- a/target/avr/cpu.h +++ b/target/avr/cpu.h @@ -21,8 +21,17 @@ #ifndef QEMU_AVR_CPU_H #define QEMU_AVR_CPU_H +#include "cpu-qom.h" #include "exec/cpu-defs.h" +#ifdef CONFIG_USER_ONLY +#error "AVR 8-bit does not support user mode" +#endif + +#define AVR_CPU_TYPE_SUFFIX "-" TYPE_AVR_CPU +#define AVR_CPU_TYPE_NAME(name) (name AVR_CPU_TYPE_SUFFIX) +#define CPU_RESOLVING_TYPE TYPE_AVR_CPU + #define TCG_GUEST_DEFAULT_MO 0 /* @@ -63,4 +72,134 @@ */ #define OFFSET_IO_REGISTERS (OFFSET_DATA + NUMBER_OF_CPU_REGISTERS) +typedef struct CPUAVRState CPUAVRState; + +struct CPUAVRState { + uint32_t pc_w; /* 0x003fffff up to 22 bits */ + + uint32_t sregC; /* 0x00000001 1 bit */ + uint32_t sregZ; /* 0x00000001 1 bit */ + uint32_t sregN; /* 0x00000001 1 bit */ + uint32_t sregV; /* 0x00000001 1 bit */ + uint32_t sregS; /* 0x00000001 1 bit */ + uint32_t sregH; /* 0x00000001 1 bit */ + uint32_t sregT; /* 0x00000001 1 bit */ + uint32_t sregI; /* 0x00000001 1 bit */ + + uint32_t rampD; /* 0x00ff0000 8 bits */ + uint32_t rampX; /* 0x00ff0000 8 bits */ + uint32_t rampY; /* 0x00ff0000 8 bits */ + uint32_t rampZ; /* 0x00ff0000 8 bits */ + uint32_t eind; /* 0x00ff0000 8 bits */ + + uint32_t r[NUMBER_OF_CPU_REGISTERS]; /* 8 bits each */ + uint32_t sp; /* 16 bits */ + + uint32_t skip; /* if set skip instruction */ + + uint64_t intsrc; /* interrupt sources */ + bool fullacc; /* CPU/MEM if true MEM only otherwise */ + + uint64_t features; +}; + +/** + * AVRCPU: + * @env: #CPUAVRState + * + * A AVR CPU. + */ +typedef struct AVRCPU { + /*< private >*/ + CPUState parent_obj; + /*< public >*/ + + CPUNegativeOffsetState neg; + CPUAVRState env; +} AVRCPU; + +void avr_cpu_do_interrupt(CPUState *cpu); +bool avr_cpu_exec_interrupt(CPUState *cpu, int int_req); +hwaddr avr_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); + +#define cpu_list avr_cpu_list +#define cpu_signal_handler cpu_avr_signal_handler +#define cpu_mmu_index avr_cpu_mmu_index + +static inline int avr_cpu_mmu_index(CPUAVRState *env, bool ifetch) +{ + return ifetch ? MMU_CODE_IDX : MMU_DATA_IDX; +} + +void avr_cpu_tcg_init(void); + +void avr_cpu_list(void); +int cpu_avr_exec(CPUState *cpu); +int cpu_avr_signal_handler(int host_signum, void *pinfo, void *puc); +int avr_cpu_memory_rw_debug(CPUState *cs, vaddr address, uint8_t *buf, + int len, bool is_write); + +enum { + TB_FLAGS_FULL_ACCESS = 1, + TB_FLAGS_SKIP = 2, +}; + +static inline void cpu_get_tb_cpu_state(CPUAVRState *env, target_ulong *pc, + target_ulong *cs_base, uint32_t *pflags) +{ + uint32_t flags = 0; + + *pc = env->pc_w * 2; + *cs_base = 0; + + if (env->fullacc) { + flags |= TB_FLAGS_FULL_ACCESS; + } + if (env->skip) { + flags |= TB_FLAGS_SKIP; + } + + *pflags = flags; +} + +static inline int cpu_interrupts_enabled(CPUAVRState *env) +{ + return env->sregI != 0; +} + +static inline uint8_t cpu_get_sreg(CPUAVRState *env) +{ + uint8_t sreg; + sreg = (env->sregC) << 0 + | (env->sregZ) << 1 + | (env->sregN) << 2 + | (env->sregV) << 3 + | (env->sregS) << 4 + | (env->sregH) << 5 + | (env->sregT) << 6 + | (env->sregI) << 7; + return sreg; +} + +static inline void cpu_set_sreg(CPUAVRState *env, uint8_t sreg) +{ + env->sregC = (sreg >> 0) & 0x01; + env->sregZ = (sreg >> 1) & 0x01; + env->sregN = (sreg >> 2) & 0x01; + env->sregV = (sreg >> 3) & 0x01; + env->sregS = (sreg >> 4) & 0x01; + env->sregH = (sreg >> 5) & 0x01; + env->sregT = (sreg >> 6) & 0x01; + env->sregI = (sreg >> 7) & 0x01; +} + +bool avr_cpu_tlb_fill(CPUState *cs, vaddr address, int size, + MMUAccessType access_type, int mmu_idx, + bool probe, uintptr_t retaddr); + +typedef CPUAVRState CPUArchState; +typedef AVRCPU ArchCPU; + +#include "exec/cpu-all.h" + #endif /* !defined (QEMU_AVR_CPU_H) */ diff --git a/target/avr/cpu.c b/target/avr/cpu.c new file mode 100644 index 0000000000..7895a5ecaa --- /dev/null +++ b/target/avr/cpu.c @@ -0,0 +1,207 @@ +/* + * QEMU AVR CPU + * + * Copyright (c) 2019-2020 Michael Rolnik + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + * + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu/qemu-print.h" +#include "exec/exec-all.h" +#include "cpu.h" +#include "disas/dis-asm.h" + +static void avr_cpu_set_pc(CPUState *cs, vaddr value) +{ + AVRCPU *cpu = AVR_CPU(cs); + + cpu->env.pc_w = value / 2; /* internally PC points to words */ +} + +static bool avr_cpu_has_work(CPUState *cs) +{ + AVRCPU *cpu = AVR_CPU(cs); + CPUAVRState *env = &cpu->env; + + return (cs->interrupt_request & (CPU_INTERRUPT_HARD | CPU_INTERRUPT_RESET)) + && cpu_interrupts_enabled(env); +} + +static void avr_cpu_synchronize_from_tb(CPUState *cs, TranslationBlock *tb) +{ + AVRCPU *cpu = AVR_CPU(cs); + CPUAVRState *env = &cpu->env; + + env->pc_w = tb->pc / 2; /* internally PC points to words */ +} + +static void avr_cpu_reset(DeviceState *ds) +{ + CPUState *cs = CPU(ds); + AVRCPU *cpu = AVR_CPU(cs); + AVRCPUClass *mcc = AVR_CPU_GET_CLASS(cpu); + CPUAVRState *env = &cpu->env; + + mcc->parent_reset(ds); + + env->pc_w = 0; + env->sregI = 1; + env->sregC = 0; + env->sregZ = 0; + env->sregN = 0; + env->sregV = 0; + env->sregS = 0; + env->sregH = 0; + env->sregT = 0; + + env->rampD = 0; + env->rampX = 0; + env->rampY = 0; + env->rampZ = 0; + env->eind = 0; + env->sp = 0; + + env->skip = 0; + + memset(env->r, 0, sizeof(env->r)); + + tlb_flush(cs); +} + +static void avr_cpu_disas_set_info(CPUState *cpu, disassemble_info *info) +{ + info->mach = bfd_arch_avr; + info->print_insn = NULL; +} + +static void avr_cpu_realizefn(DeviceState *dev, Error **errp) +{ + CPUState *cs = CPU(dev); + AVRCPUClass *mcc = AVR_CPU_GET_CLASS(dev); + Error *local_err = NULL; + + cpu_exec_realizefn(cs, &local_err); + if (local_err != NULL) { + error_propagate(errp, local_err); + return; + } + qemu_init_vcpu(cs); + cpu_reset(cs); + + mcc->parent_realize(dev, errp); +} + +static void avr_cpu_set_int(void *opaque, int irq, int level) +{ + AVRCPU *cpu = opaque; + CPUAVRState *env = &cpu->env; + CPUState *cs = CPU(cpu); + + uint64_t mask = (1ull << irq); + if (level) { + env->intsrc |= mask; + cpu_interrupt(cs, CPU_INTERRUPT_HARD); + } else { + env->intsrc &= ~mask; + if (env->intsrc == 0) { + cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); + } + } +} + +static void avr_cpu_initfn(Object *obj) +{ + AVRCPU *cpu = AVR_CPU(obj); + + cpu_set_cpustate_pointers(cpu); + + /* Set the number of interrupts supported by the CPU. */ + qdev_init_gpio_in(DEVICE(cpu), avr_cpu_set_int, + sizeof(cpu->env.intsrc) * 8); +} + +static ObjectClass *avr_cpu_class_by_name(const char *cpu_model) +{ + ObjectClass *oc; + + oc = object_class_by_name(cpu_model); + if (object_class_dynamic_cast(oc, TYPE_AVR_CPU) == NULL || + object_class_is_abstract(oc)) { + oc = NULL; + } + return oc; +} + +static void avr_cpu_dump_state(CPUState *cs, FILE *f, int flags) +{ + AVRCPU *cpu = AVR_CPU(cs); + CPUAVRState *env = &cpu->env; + int i; + + qemu_fprintf(f, "\n"); + qemu_fprintf(f, "PC: %06x\n", env->pc_w); + qemu_fprintf(f, "SP: %04x\n", env->sp); + qemu_fprintf(f, "rampD: %02x\n", env->rampD >> 16); + qemu_fprintf(f, "rampX: %02x\n", env->rampX >> 16); + qemu_fprintf(f, "rampY: %02x\n", env->rampY >> 16); + qemu_fprintf(f, "rampZ: %02x\n", env->rampZ >> 16); + qemu_fprintf(f, "EIND: %02x\n", env->eind >> 16); + qemu_fprintf(f, "X: %02x%02x\n", env->r[27], env->r[26]); + qemu_fprintf(f, "Y: %02x%02x\n", env->r[29], env->r[28]); + qemu_fprintf(f, "Z: %02x%02x\n", env->r[31], env->r[30]); + qemu_fprintf(f, "SREG: [ %c %c %c %c %c %c %c %c ]\n", + env->sregI ? 'I' : '-', + env->sregT ? 'T' : '-', + env->sregH ? 'H' : '-', + env->sregS ? 'S' : '-', + env->sregV ? 'V' : '-', + env->sregN ? '-' : 'N', /* Zf has negative logic */ + env->sregZ ? 'Z' : '-', + env->sregC ? 'I' : '-'); + qemu_fprintf(f, "SKIP: %02x\n", env->skip); + + qemu_fprintf(f, "\n"); + for (i = 0; i < ARRAY_SIZE(env->r); i++) { + qemu_fprintf(f, "R[%02d]: %02x ", i, env->r[i]); + + if ((i % 8) == 7) { + qemu_fprintf(f, "\n"); + } + } + qemu_fprintf(f, "\n"); +} + +static void avr_cpu_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + CPUClass *cc = CPU_CLASS(oc); + AVRCPUClass *mcc = AVR_CPU_CLASS(oc); + + mcc->parent_realize = dc->realize; + dc->realize = avr_cpu_realizefn; + + device_class_set_parent_reset(dc, avr_cpu_reset, &mcc->parent_reset); + + cc->class_by_name = avr_cpu_class_by_name; + + cc->has_work = avr_cpu_has_work; + cc->dump_state = avr_cpu_dump_state; + cc->set_pc = avr_cpu_set_pc; + cc->disas_set_info = avr_cpu_disas_set_info; + cc->tcg_initialize = avr_cpu_tcg_init; + cc->synchronize_from_tb = avr_cpu_synchronize_from_tb; +}